Background

  • This session will demonstrate fitting the Besag, York, and Mollié (1991) conditional autoregressive (CAR) model for disease mapping and ecological regression applications involving areal data.

  • We will use a classic data set first reported by Clayton and Kaldor (1987) that describes the incidence of male lip cancer within Scottish administration districts from 1975 to 1980.

  • The data set was subsequently expanded to include the number of male population-years at-risk (Cressie, 1993) and the expected number of lip cancer cases and percentage of males employed in agriculture, fishing and forestry (AFF) (Stern & Cressie, 1999) in each district.

  • The map of Scottish administrative districts is a post-processed version of the Scotland.map S-Plus boundary file that was included in WinBUGS 1.4.3, a state-of-the-art 32-bit program for Bayesian inference when released on 6th August 2007 — now, not so much…

  • All data are available in a single ZIP archive available on the GeoDa Centre GuitHub repository and are described in Table 1 (columns 1 nd 2), along with the subset of variables used for this demonstration (columns 3 and 4)

Table 1: Data summary for Scottish lip cancer data set available from GeoDa Centre GitHub repository

GeoDa variable GeoDa description PUBH5125 variable PUBH5125 description
CODENO Code converted to numeric (drop w prefix) CODENO Code converted to numeric (drop w prefix)
AREA District polygon area AREA District polygon area
PERIMETER District polygon perimeter PERIMETER District polygon perimeter
RECORD_ID Unique ID RECORD_ID Unique ID
DISTRICT District number 1-56 dist_code District number 1-56
NAME Name of districts from Cressie (1993) dist_name Name of districts from Cressie (1993)
CODE District code from WinBugs CODE District code from WinBugs
CANCER Lip cancer cases from Cressie (1993) obs_ca Lip cancer cases from Cressie (1993)
POP Population years at risk from Cressie (1993) dist_popn Population years at risk from Cressie (1993)
CEXP Expected cases from Lawson et al. (1999) exp_ca Expected cases from Stern & Cressie (1999)
AFF Outdoor industry from Lawson et al. (1999) pct_aff Outdoor industry from Stern & Cressie (1999)

Aims of this session

  1. Download spatial boundaries and observed and expected cases of incident male lip cancer in Scottish districts from 1975–1980
  2. Calculate and map the standardised incidence ratios (SIR) and their precision from the raw data
  3. Create a queen adjacency matrix that identifies the neighbours for each Scottish district sharing a common boundary (edge) or point (vertex)
  4. Fit a Besag, York and Mollié (BYM) conditional autoregressive (CAR) model to produce a smoothed disease map of lip cancer risk in Scotland over the study period
    4.1 Calculate and map residual risk estimated by \(e^{s_i + u_i}\)
    4.2 Decompose and map residual risk due to spatially structured \((e^{s_i})\) and unstructured \((e^{u_i})\) effects
    4.3 Estimate proportion of residual risk in male lip cancer incidence due to spatial effects \(\rho = \sigma^{2}_{s} / (\sigma^{2}_{s} + \sigma^{2}_{u})\)
    4.4 Calculate posterior probability for increased residual risk of male lip cancer incidence for each district

Preliminaries

Required packages

These are the packages that need to be installed and attached to complete the analysis.

{ # Check for and install pacman package if missing
  
  if(base::require(pacman, quietly = TRUE) == FALSE){install.packages("pacman")}
  
  # list required packages
  
  reqPackages <- c("tidyverse",      # An opinionated collection of R packages designed for data science
                   "CARBayes",       # Spatial Generalised Linear Mixed Models for Areal Unit Data
                   "coda",           # A package for Output Analysis and Diagnostics for MCMC
                   "epitools",       # A package for epidemiological analysis
                   "ggmcmc",         # MCMC diagnostics with ggplot
                   "ggpubr",         # A package for producing publication-ready plots 
                   "ggrepel",        # A package for position non-overlapping text labels with 'ggplot2'
                   "GGally",         # A package to do pairplots
                   "knitr",          # A general-purpose tool for dynamic report generation in R
                   "nimble",         # A package for performing MCMC in R
                   "patchwork",      # A package to combine plots
                   "rmarkdown",      # A package for creating dynamic documents for R
                   "RColorBrewer",   # A package of colour palettes
                   "scales",         # Scale functions for visualization
                   "sf",             # Simple features for R
                   "spdep")          # A package to calculate neighbors)
  
  # Load (and install if missing) other required packages
  
  pacman::p_load(char = reqPackages, install = TRUE)
  
  # Check required packages are loaded
  
  pacman::p_loaded(char = reqPackages)
  
}
##    tidyverse     CARBayes         coda     epitools       ggmcmc       ggpubr      ggrepel       GGally        knitr       nimble    patchwork    rmarkdown RColorBrewer 
##         TRUE         TRUE         TRUE         TRUE         TRUE         TRUE         TRUE         TRUE         TRUE         TRUE         TRUE         TRUE         TRUE 
##       scales           sf        spdep 
##         TRUE         TRUE         TRUE

R environment

This output shows the R environment of the analysis; it includes dependencies loaded / attached by packages above.

# Get session information

utils::sessionInfo()
## R version 4.3.3 (2024-02-29 ucrt)
## Platform: x86_64-w64-mingw32/x64 (64-bit)
## Running under: Windows 10 x64 (build 19045)
## 
## Matrix products: default
## 
## 
## locale:
## [1] LC_COLLATE=English_Australia.utf8  LC_CTYPE=English_Australia.utf8    LC_MONETARY=English_Australia.utf8 LC_NUMERIC=C                      
## [5] LC_TIME=English_Australia.utf8    
## 
## time zone: Australia/Sydney
## tzcode source: internal
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] spdep_1.3-11       spData_2.3.4       sf_1.0-16          scales_1.4.0       RColorBrewer_1.1-3 rmarkdown_2.29     patchwork_1.3.0    nimble_1.3.0      
##  [9] knitr_1.50         GGally_2.2.1       ggrepel_0.9.5      ggpubr_0.6.0       ggmcmc_1.5.1.1     epitools_0.5-10.1  coda_0.19-4.1      CARBayes_6.1.1    
## [17] Rcpp_1.0.12        MASS_7.3-60.0.1    lubridate_1.9.3    forcats_1.0.0      stringr_1.5.1      dplyr_1.1.4        purrr_1.0.2        readr_2.1.5       
## [25] tidyr_1.3.1        tibble_3.2.1       ggplot2_3.5.1      tidyverse_2.0.0    pacman_0.5.1      
## 
## loaded via a namespace (and not attached):
##  [1] DBI_1.2.2           deldir_2.0-4        s2_1.1.6            rlang_1.1.3         magrittr_2.0.3      e1071_1.7-14        compiler_4.3.3      png_0.1-8          
##  [9] vctrs_0.6.5         quantreg_5.97       pkgconfig_2.0.3     wk_0.9.1            shape_1.4.6.1       fastmap_1.1.1       backports_1.4.1     mcmc_0.9-8         
## [17] leafem_0.2.3        utf8_1.2.4          pracma_2.4.4        tzdb_0.4.0          MatrixModels_0.5-3  xfun_0.52           satellite_1.0.5     glmnet_4.1-8       
## [25] cachem_1.0.8        jsonlite_1.8.8      CARBayesdata_3.0    mapview_2.11.2      terra_1.7-83        broom_1.0.5         parallel_4.3.3      R6_2.5.1           
## [33] bslib_0.7.0         stringi_1.8.3       car_3.1-2           boot_1.3-29         numDeriv_2016.8-1.1 jquerylib_0.1.4     iterators_1.0.14    base64enc_0.1-3    
## [41] Matrix_1.6-5        splines_4.3.3       igraph_2.0.3        timechange_0.3.0    tidyselect_1.2.1    abind_1.4-5         rstudioapi_0.16.0   yaml_2.3.10        
## [49] codetools_0.2-19    lattice_0.22-5      plyr_1.8.9          withr_3.0.0         evaluate_0.23       survival_3.5-8      ggstats_0.6.0       units_0.8-5        
## [57] proxy_0.4-27        pillar_1.9.0        carData_3.0-5       KernSmooth_2.23-22  foreach_1.5.2       stats4_4.3.3        generics_0.1.3      sp_2.1-3           
## [65] truncnorm_1.0-9     hms_1.1.3           class_7.3-22        glue_1.7.0          tools_4.3.3         SparseM_1.81        ggsignif_0.6.4      dotCall64_1.2      
## [73] grid_4.3.3          MCMCpack_1.7-1      crosstalk_1.2.1     colorspace_2.1-0    raster_3.6-30       cli_3.6.2           spam_2.11-1         fansi_1.0.6        
## [81] gtable_0.3.5        rstatix_0.7.2       sass_0.4.9          digest_0.6.35       classInt_0.4-10     htmlwidgets_1.6.4   farver_2.1.1        htmltools_0.5.8.1  
## [89] lifecycle_1.0.4     leaflet_2.2.2

Data

In this section we extract, transform and load (ETL) the lip cancer data. This can be done manually, but the folded code chunk show how it can be done entirely withi R.

Download data

The following output section shows all the files contained in the GeoDa Center ZIP file we downloaded using the folded Code chunk. We will use the scotlip/scotlip.gpkg GeoPackage data file with record index 79 at row 40 for our analysis.

# Download Scottish lip cancer data --------------------------------------------

# Available from the the GeoDa Center as a zipped archive from:
# https://geodacenter.github.io/data-and-lab/scotlip/ but can be downloaded
# directly within R

# Download ZIP file to temp directory

data.url <- "https://geodacenter.github.io/data-and-lab/data/scotlip.zip"

utils::download.file(data.url,
                     base::file.path(base::tempdir(), "scotlip.zip"),
                     mode = "wb")

# View the contents of the zip file

utils::unzip(zipfile = base::file.path(base::tempdir(), "scotlip.zip"), list = TRUE) %>%
              base::as.data.frame() %>%
              arrange(Name) %>%
  dplyr::pull(Name)
##  [1] "__MACOSX/"                                                       "__MACOSX/._scotlip"                                             
##  [3] "__MACOSX/scotlip/"                                               "__MACOSX/scotlip/._.DS_Store"                                   
##  [5] "__MACOSX/scotlip/._scotdistricts.dbf"                            "__MACOSX/scotlip/._scotdistricts.shp"                           
##  [7] "__MACOSX/scotlip/._scotdistricts.shx"                            "__MACOSX/scotlip/._scotdistricts.txt"                           
##  [9] "__MACOSX/scotlip/._scotlip.dbf"                                  "__MACOSX/scotlip/._scotlip.shp"                                 
## [11] "__MACOSX/scotlip/._scotlip.shx"                                  "__MACOSX/scotlip/._scotlip_metadata.html"                       
## [13] "__MACOSX/scotlip/._scotlipdata.dbf"                              "__MACOSX/scotlip/._style.css"                                   
## [15] "scotlip/"                                                        "scotlip/.DS_Store"                                              
## [17] "scotlip/scotdistricts.csv"                                       "scotlip/scotdistricts.dbf"                                      
## [19] "scotlip/scotdistricts.geojson"                                   "scotlip/scotdistricts.gpkg"                                     
## [21] "scotlip/scotdistricts.mid"                                       "scotlip/scotdistricts.mif"                                      
## [23] "scotlip/scotdistricts.shp"                                       "scotlip/scotdistricts.shx"                                      
## [25] "scotlip/scotdistricts.sqlite"                                    "scotlip/scotdistricts.txt"                                      
## [27] "scotlip/scotdistricts.xlsx"                                      "scotlip/scotlip.csv"                                            
## [29] "scotlip/scotlip.dbf"                                             "scotlip/scotlip.gdb/"                                           
## [31] "scotlip/scotlip.gdb/a00000001.TablesByName.atx"                  "scotlip/scotlip.gdb/a00000001.gdbindexes"                       
## [33] "scotlip/scotlip.gdb/a00000001.gdbtable"                          "scotlip/scotlip.gdb/a00000001.gdbtablx"                         
## [35] "scotlip/scotlip.gdb/a00000002.gdbtable"                          "scotlip/scotlip.gdb/a00000002.gdbtablx"                         
## [37] "scotlip/scotlip.gdb/a00000003.gdbindexes"                        "scotlip/scotlip.gdb/a00000003.gdbtable"                         
## [39] "scotlip/scotlip.gdb/a00000003.gdbtablx"                          "scotlip/scotlip.gdb/a00000004.CatItemsByPhysicalName.atx"       
## [41] "scotlip/scotlip.gdb/a00000004.CatItemsByType.atx"                "scotlip/scotlip.gdb/a00000004.FDO_UUID.atx"                     
## [43] "scotlip/scotlip.gdb/a00000004.gdbindexes"                        "scotlip/scotlip.gdb/a00000004.gdbtable"                         
## [45] "scotlip/scotlip.gdb/a00000004.gdbtablx"                          "scotlip/scotlip.gdb/a00000004.spx"                              
## [47] "scotlip/scotlip.gdb/a00000005.CatItemTypesByName.atx"            "scotlip/scotlip.gdb/a00000005.CatItemTypesByParentTypeID.atx"   
## [49] "scotlip/scotlip.gdb/a00000005.CatItemTypesByUUID.atx"            "scotlip/scotlip.gdb/a00000005.gdbindexes"                       
## [51] "scotlip/scotlip.gdb/a00000005.gdbtable"                          "scotlip/scotlip.gdb/a00000005.gdbtablx"                         
## [53] "scotlip/scotlip.gdb/a00000006.CatRelsByDestinationID.atx"        "scotlip/scotlip.gdb/a00000006.CatRelsByOriginID.atx"            
## [55] "scotlip/scotlip.gdb/a00000006.CatRelsByType.atx"                 "scotlip/scotlip.gdb/a00000006.FDO_UUID.atx"                     
## [57] "scotlip/scotlip.gdb/a00000006.gdbindexes"                        "scotlip/scotlip.gdb/a00000006.gdbtable"                         
## [59] "scotlip/scotlip.gdb/a00000006.gdbtablx"                          "scotlip/scotlip.gdb/a00000007.CatRelTypesByBackwardLabel.atx"   
## [61] "scotlip/scotlip.gdb/a00000007.CatRelTypesByDestItemTypeID.atx"   "scotlip/scotlip.gdb/a00000007.CatRelTypesByForwardLabel.atx"    
## [63] "scotlip/scotlip.gdb/a00000007.CatRelTypesByName.atx"             "scotlip/scotlip.gdb/a00000007.CatRelTypesByOriginItemTypeID.atx"
## [65] "scotlip/scotlip.gdb/a00000007.CatRelTypesByUUID.atx"             "scotlip/scotlip.gdb/a00000007.gdbindexes"                       
## [67] "scotlip/scotlip.gdb/a00000007.gdbtable"                          "scotlip/scotlip.gdb/a00000007.gdbtablx"                         
## [69] "scotlip/scotlip.gdb/a00000009.gdbindexes"                        "scotlip/scotlip.gdb/a00000009.gdbtable"                         
## [71] "scotlip/scotlip.gdb/a00000009.gdbtablx"                          "scotlip/scotlip.gdb/a00000009.spx"                              
## [73] "scotlip/scotlip.gdb/a0000000a.gdbindexes"                        "scotlip/scotlip.gdb/a0000000a.gdbtable"                         
## [75] "scotlip/scotlip.gdb/a0000000a.gdbtablx"                          "scotlip/scotlip.gdb/a0000000a.spx"                              
## [77] "scotlip/scotlip.gdb/gdb"                                         "scotlip/scotlip.gdb/timestamps"                                 
## [79] "scotlip/scotlip.gpkg"                                            "scotlip/scotlip.mid"                                            
## [81] "scotlip/scotlip.mif"                                             "scotlip/scotlip.shp"                                            
## [83] "scotlip/scotlip.shx"                                             "scotlip/scotlip.sqlite"                                         
## [85] "scotlip/scotlip.xlsx"                                            "scotlip/scotlip_metadata.html"                                  
## [87] "scotlip/scotlipdata.dbf"                                         "scotlip/scotlips.geojson"                                       
## [89] "scotlip/style.css"

Extract data

A GeoPackage is an open-source, standards-based and platform independent file format for storing both spatial and attribute data in a single, portable file. In this code chunk, we extract the GeoPackage and then query it to identify the correct correct data layer to use.

## Extract the scotlip.gpkg geopackage data file (row 79) ----------------------

# See https://en.wikipedia.org/wiki/GeoPackage for a description of the 
# geopackage data format. 

# Extract the scotlip.gpkg geopackage from the ZIP file

utils::unzip(zipfile = base::file.path(base::tempdir(), "scotlip.zip"),
             files = "scotlip/scotlip.gpkg",
             exdir = base::tempdir(),
             junkpaths = TRUE) # Only use the file name of the stored file path when extracting

# List GeoPack layers

base::cat("List GeoPackage layers:",
          "\n\n",
          base::as.character(base::data.frame(layers = sf::st_layers(base::file.path(base::tempdir(), "scotlip.gpkg"))$name)))
## List GeoPackage layers: 
## 
##  scotlip

Load data

As the GeoPackage contains a single layer (scotlip), we read this into R, only to be disappointed that the wrong coordinate reference system (WGS 80) has been assigned to the spatial data. The correct projected coordinate reference system for these data are OSGB36 / British National Grid, which we need to apply manually.

# Read scotlip.gpkg layer, which includes data and geometry.

# Note: I have set the coordinate reference system (CRS) to NA because the CRS
#       supplied in the geopack (WGS 80) is incorrect.You can easily tell this 
#       by looking at he bounding box values. WGS 80 is a geographic coordinate
#       system with decimal degree units, so both the minima nor maxima values
#       are bounded by -180 to +180 degrees. The values here are all grater than
#       450,000, which indicate a projected coordinate system of easting and
#       northing in linear meters

src_sf <- sf::st_read(dsn = base::file.path(base::tempdir(), "scotlip.gpkg"),
                      layer = "scotlip",
                      crs = NA_crs_) # Remove the wrong coordinate reference system (CRS) assigned in the geopackage
## Reading layer `scotlip' from data source `C:\Users\Darren\AppData\Local\Temp\Rtmpqek4tt\scotlip.gpkg' using driver `GPKG'
## Simple feature collection with 56 features and 11 fields
## Geometry type: POLYGON
## Dimension:     XY
## Bounding box:  xmin: 95631 ymin: 530297 xmax: 454570 ymax: 1203008
## CRS:           NA
# After some fossicking around, I was able to determine the correct projected coordinate
# system for these data is OSGB36 / British National Grid, which we now apply using
# the European Petroleum Survey Group (EPSG) code 27700 

sf::st_crs(src_sf) <- 27700 # see https://epsg.io/27700 for CRS details

# Check that the CRS has been applied to the spatial data 

print(src_sf)
## Simple feature collection with 56 features and 11 fields
## Geometry type: POLYGON
## Dimension:     XY
## Bounding box:  xmin: 95631 ymin: 530297 xmax: 454570 ymax: 1203008
## Projected CRS: OSGB36 / British National Grid
## First 10 features:
##    CODENO       AREA PERIMETER RECORD_ID DISTRICT          NAME  CODE CANCER    POP CEXP AFF                           geom
## 1    6126  974002000    184951         1        1 Skye-Lochalsh w6126      9  28324 1.38  16 POLYGON ((214091.9 841215.2...
## 2    6016 1461990000    178224         2        2  Banff-Buchan w6016     39 231337 8.66  16 POLYGON ((383866 865862, 39...
## 3    6121 1753090000    179177         3        3     Caithness w6121     11  83190 3.04  10 POLYGON ((311487 968650, 32...
## 4    5601  898599000    128777         4        4  Berwickshire w5601      9  51710 2.53  24 POLYGON ((377180 672603, 38...
## 5    6125 5109870000    580792         5        5 Ross-Cromarty w6125     15 129271 4.26  10 POLYGON ((278680.1 882371.8...
## 6    6554  422639000    118433         6        6         Okney w6554      8  53199 2.40  24 POLYGON ((328040 1011192, 3...
## 7    6019 2267340000    259143         7        7         Moray w6019     26 245513 8.11  10 POLYGON ((348968 868724, 35...
## 8    6655  157575000     54859         8        8      Shetland w6655      7  62603 2.30   7 POLYGON ((450593 1203008, 4...
## 9    6123 4129180000    543208         9        9      Lochaber w6123      6  59183 1.98   7 POLYGON ((192646 807178, 21...
## 10   6017 2084800000    260668        10       10        Gordon w6017     20 165554 6.63  16 POLYGON ((397156 840640, 39...

Enrich data

In this final preparation step, we wrangle the remaining attribute data (e.g. some district names need tidying up) into an intuitive analysis-ready format and enrich it by adding standardised incidence ratios and their exact Poisson 95% confidence intervals. We will also calculate indicies of estimate precision based on expected and observed lip cancer cases.

# Clean and enrich sf for data analysis

lip_sf <- src_sf %>%
  
  # Rename columns to lower case
  
  dplyr::rename_with(base::tolower) %>%
  
  # Limit to selected (renamed) variables
  
  dplyr::select(dist_code = district, dist_name = name, dist_popn = pop, obs_ca = cancer, exp_ca = cexp, pct_aff = aff) %>%
  
  # Correct typographical errors in district names
  
  dplyr::mutate(dplyr::across(dist_name, ~ dplyr::case_when(. == "EastKilbride" ~ "East Kilbride",
                                                            . == "EastLothian" ~ "East Lothian",
                                                            . == "NEFife" ~ "NE Fife",
                                                            . == "WesternIsles" ~ "Western Isles",
                                                            . == "WestLothian" ~ "West Lothian",
                                                            .default = .))) %>%
  
  # Calculate standardised incidence ratios (SIR) with exact Poisson 95% 
  # confidence intervals using using pois.exact function from epitools.
  
  dplyr::bind_cols(base::data.frame(epitools::pois.exact(pull(., obs_ca), pull(., exp_ca)) %>%
                                      dplyr::select(obs_sir_est = rate,
                                                    obs_sir_l95 = lower,
                                                    obs_sir_u95  = upper))) %>%
  
  # Calculate probability values for SIR
  
  dplyr::mutate(obs_sir_sig = stats::dpois(obs_ca, exp_ca),
                obs_sir_cat = dplyr::case_when(obs_sir_est < 1 & obs_sir_sig < 0.005 ~ "--",
                                               obs_sir_est < 1 & obs_sir_sig < 0.025 ~ "-",
                                               obs_sir_est > 1 & obs_sir_sig < 0.005 ~ "++",
                                               obs_sir_est > 1 & obs_sir_sig < 0.025 ~ "+",
                                               .default = "")) %>%
  
  # Calculate standard and relative errors for SIR
  
  dplyr::mutate(obs_sir_se = base::sqrt(obs_ca) / exp_ca,
                obs_sir_rse = obs_sir_se / obs_sir_est,   # Also estimated by RSE = 1 / base::sqrt(obs_ca),
                exp_sir_rse = 1 / exp_ca) %>%
  
  # # Add district centroids (note use of sf::st_geometry - avoids warnings about assumed attribute distributions
  # 
  # dplyr::bind_cols(sf::st_coordinates(sf::st_centroid(sf::st_geometry(.))) %>%
  #                    base::as.data.frame() %>%
  #                    dplyr::rename(centroid_x = X, centroid_y = Y)) %>%
  
  # Add variable labels
  
  labelled::set_variable_labels(dist_code = "District code",
                                dist_name = "District name",
                                dist_popn = "Male population years at risk (1975-1980)",
                                obs_ca = "Observed male lip cancer cases (1975-1980)",
                                exp_ca = "Expected male lip cancer cases (1975-1980)",
                                pct_aff = "Percent of male population working in agriculture, fishing or forestry",
                                obs_sir_est = "Observed SIR estimate",
                                obs_sir_l95 = "Observed SIR lower 95% CI",
                                obs_sir_u95 = "Observed SIR upper 95% CI",
                                obs_sir_sig = "Probability value for observed SIR estimate",
                                obs_sir_cat = "Probability category for observed SIR estimate",
                                obs_sir_se = "Observed SIR standard error",
                                obs_sir_rse = "Observed SIR relative standard error",
                                exp_sir_rse = "Proportional precision of SIR from expected cases",
                                # centroid_x = "Centroid X coordinate (EPSG:27700)",
                                # centroid_y = "Centroid Y coordinate (EPSG:27700)",
                                geom = "Geometry (OSGB 1936 / British National Grid)") %>%
  
  # Move geometry column to end of data set
  
  dplyr::select(dplyr::everything(), -geom, geom)

# View the data set

print(lip_sf, digits = 2, n = 56)
## Simple feature collection with 56 features and 14 fields
## Geometry type: POLYGON
## Dimension:     XY
## Bounding box:  xmin: 95631 ymin: 530297 xmax: 454570 ymax: 1203008
## Projected CRS: OSGB36 / British National Grid
##    dist_code     dist_name dist_popn obs_ca exp_ca pct_aff obs_sir_est obs_sir_l95 obs_sir_u95 obs_sir_sig obs_sir_cat obs_sir_se obs_sir_rse exp_sir_rse
## 1          1 Skye-Lochalsh     28324      9    1.4      16        6.52      2.9822       12.38     1.3e-05          ++      2.174        0.33       0.725
## 2          2  Banff-Buchan    231337     39    8.7      16        4.50      3.2024        6.16     3.1e-14          ++      0.721        0.16       0.115
## 3          3     Caithness     83190     11    3.0      10        3.62      1.8063        6.47     2.5e-04          ++      1.091        0.30       0.329
## 4          4  Berwickshire     51710      9    2.5      24        3.56      1.6266        6.75     9.3e-04          ++      1.186        0.33       0.395
## 5          5 Ross-Cromarty    129271     15    4.3      10        3.52      1.9707        5.81     3.0e-05          ++      0.909        0.26       0.235
## 6          6         Okney     53199      8    2.4      24        3.33      1.4391        6.57     2.5e-03          ++      1.179        0.35       0.417
## 7          7         Moray    245513     26    8.1      10        3.21      2.0942        4.70     3.2e-07          ++      0.629        0.20       0.123
## 8          8      Shetland     62603      7    2.3       7        3.04      1.2236        6.27     6.8e-03           +      1.150        0.38       0.435
## 9          9      Lochaber     59183      6    2.0       7        3.03      1.1121        6.60     1.2e-02           +      1.237        0.41       0.505
## 10        10        Gordon    165554     20    6.6      16        3.02      1.8426        4.66     1.5e-05          ++      0.675        0.22       0.151
## 11        11 Western Isles     87815     13    4.4       7        2.95      1.5732        5.05     4.6e-04          ++      0.819        0.28       0.227
## 12        12    Sutherland     37521      5    1.8      16        2.79      0.9070        6.52     2.6e-02                  1.249        0.45       0.559
## 13        13         Nairn     29374      3    1.1      10        2.78      0.5728        8.12     7.1e-02                  1.604        0.58       0.926
## 14        14       Wigtown     86444      8    3.3      24        2.42      1.0435        4.76     1.3e-02           +      0.855        0.35       0.302
## 15        15       NE Fife    185472     17    7.8       7        2.17      1.2632        3.47     1.8e-03          ++      0.526        0.24       0.128
## 16        16    Kincardine    111665      9    4.5      16        1.98      0.9045        3.75     2.4e-02           +      0.659        0.33       0.220
## 17        17      Badenoch     27075      2    1.1      10        1.87      0.2264        6.75     2.0e-01                  1.322        0.71       0.935
## 18        18       Ettrick     94145      7    4.2       7        1.67      0.6733        3.45     6.8e-02                  0.633        0.38       0.239
## 19        19     Inverness    162867      9    5.5       7        1.63      0.7442        3.09     5.3e-02                  0.542        0.33       0.181
## 20        20      Roxburgh    102697      7    4.4      10        1.58      0.6339        3.25     8.0e-02                  0.596        0.38       0.225
## 21        21         Angus    263205     16   10.5       7        1.53      0.8743        2.48     2.8e-02                  0.382        0.25       0.096
## 22        22      Aberdeen    583327     31   22.7      16        1.37      0.9291        1.94     1.8e-02           +      0.246        0.18       0.044
## 23        23   Argyll-Bute    190816     11    8.8      10        1.25      0.6261        2.24     9.2e-02                  0.378        0.30       0.114
## 24        24    Clydesdale    163818      7    5.6       7        1.25      0.5008        2.57     1.3e-01                  0.471        0.38       0.178
## 25        25     Kirkcaldy    432132     19   15.5       1        1.23      0.7394        1.92     6.3e-02                  0.282        0.23       0.065
## 26        26   Dunfermline    378946     15   12.5       1        1.20      0.6722        1.98     8.1e-02                  0.310        0.26       0.080
## 27        27     Nithsdale    163703      7    6.0       7        1.16      0.4660        2.39     1.4e-01                  0.438        0.38       0.166
## 28        28  East Lothian    231185     10    9.0       7        1.12      0.5352        2.05     1.2e-01                  0.353        0.32       0.112
## 29        29 Perth-Kinross    346041     16   14.4      10        1.11      0.6364        1.81     9.1e-02                  0.278        0.25       0.070
## 30        30  West Lothian    382702     11   10.2      10        1.08      0.5383        1.93     1.2e-01                  0.325        0.30       0.098
## 31        31  Cumnock-Doon    139148      5    4.8       7        1.05      0.3418        2.46     1.7e-01                  0.471        0.45       0.211
## 32        32     Stewartry     65448      3    2.9      24        1.04      0.2148        3.04     2.2e-01                  0.601        0.58       0.347
## 33        33    Midlothian    249667      7    7.0      10        1.00      0.4003        2.05     1.5e-01                  0.376        0.38       0.142
## 34        34      Stirling    233125      8    8.5       7        0.94      0.4049        1.85     1.4e-01                  0.332        0.35       0.117
## 35        35  Kyle-Carrick    319316     11   12.3       7        0.89      0.4457        1.60     1.1e-01                  0.269        0.30       0.081
## 36        36    Inverclyde    296238      9   10.1       0        0.89      0.4075        1.69     1.2e-01                  0.297        0.33       0.099
## 37        37   Cunninghame    391513     11   12.7      10        0.87      0.4331        1.55     1.1e-01                  0.262        0.30       0.079
## 38        38     Monklands    319072      8    9.3       1        0.86      0.3694        1.69     1.3e-01                  0.303        0.35       0.107
## 39        39     Dumbarton    231227      6    7.2      16        0.83      0.3058        1.81     1.4e-01                  0.340        0.41       0.139
## 40        40     Clydebank    156924      4    5.3       0        0.76      0.2068        1.94     1.7e-01                  0.380        0.50       0.190
## 41        41       Renfrew    617413     10   18.8       1        0.53      0.2556        0.98     1.1e-02           -      0.169        0.32       0.053
## 42        42       Falkirk    426519      8   15.8      16        0.51      0.2189        1.00     1.3e-02           -      0.179        0.35       0.063
## 43        43   Clackmannan    141294      2    4.3      16        0.46      0.0561        1.67     1.2e-01                  0.327        0.71       0.231
## 44        44    Motherwell    449231      6   14.6       0        0.41      0.1505        0.89     6.0e-03           -      0.167        0.41       0.068
## 45        45     Edinburgh   1287561     19   50.7       1        0.37      0.2255        0.58     1.9e-07          --      0.086        0.23       0.020
## 46        46    Kilmarnock    238170      3    8.2       7        0.37      0.0754        1.07     2.5e-02                  0.211        0.58       0.122
## 47        47 East Kilbride    246849      2    5.6       1        0.36      0.0433        1.29     5.8e-02                  0.253        0.71       0.179
## 48        48      Hamilton    312103      3    9.3       1        0.32      0.0662        0.94     1.2e-02           -      0.185        0.58       0.107
## 49        49       Glasgow   2316353     28   88.7       0        0.32      0.2099        0.46     3.5e-14          --      0.060        0.19       0.011
## 50        50        Dundee    547016      6   19.6       1        0.31      0.1122        0.67     2.4e-04          --      0.125        0.41       0.051
## 51        51   Cumbernauld    179194      1    3.4       1        0.29      0.0074        1.62     1.1e-01                  0.291        1.00       0.291
## 52        52      Bearsden    110707      1    3.6       0        0.28      0.0070        1.54     9.7e-02                  0.276        1.00       0.276
## 53        53      Eastwood    146112      1    5.7       1        0.17      0.0044        0.97     1.8e-02           -      0.174        1.00       0.174
## 54        54  Strathkelvin    246744      1    7.0       1        0.14      0.0036        0.79     6.2e-03           -      0.142        1.00       0.142
## 55        55     Tweeddale     38704      0    4.2      16        0.00      0.0000        0.89     1.6e-02           -      0.000         NaN       0.240
## 56        56     Annandale    103412      0    1.8      10        0.00      0.0000        2.10     1.7e-01                  0.000         NaN       0.568
##                              geom
## 1  POLYGON ((214092 841215, 21...
## 2  POLYGON ((383866 865862, 4e...
## 3  POLYGON ((311487 968650, 32...
## 4  POLYGON ((377180 672603, 38...
## 5  POLYGON ((278680 882372, 29...
## 6  POLYGON ((328040 1e+06, 321...
## 7  POLYGON ((348968 868724, 35...
## 8  POLYGON ((450593 1203008, 4...
## 9  POLYGON ((192646 807178, 21...
## 10 POLYGON ((4e+05 840640, 4e+...
## 11 POLYGON ((123439 905891, 12...
## 12 POLYGON ((3e+05 965593, 291...
## 13 POLYGON ((294866 861442, 3e...
## 14 POLYGON ((246670 587314, 25...
## 15 POLYGON ((333001 723320, 34...
## 16 POLYGON ((378244 8e+05, 392...
## 17 POLYGON ((289113 829193, 3e...
## 18 POLYGON ((347058 658756, 35...
## 19 POLYGON ((232760 848360, 23...
## 20 POLYGON ((366182 640000, 37...
## 21 POLYGON ((372557 762318, 36...
## 22 POLYGON ((393827 809112, 39...
## 23 POLYGON ((209543 742400, 23...
## 24 POLYGON ((290717 655664, 30...
## 25 POLYGON ((340000 7e+05, 328...
## 26 POLYGON ((315000 7e+05, 318...
## 27 POLYGON ((265992 6e+05, 274...
## 28 POLYGON ((332787 673159, 34...
## 29 POLYGON ((316441 776777, 31...
## 30 POLYGON ((305532 679799, 31...
## 31 POLYGON ((258712 632155, 27...
## 32 POLYGON ((248144 592429, 26...
## 33 POLYGON ((314305 659828, 33...
## 34 POLYGON ((258373 734511, 26...
## 35 POLYGON ((232714 633968, 23...
## 36 POLYGON ((236768 673889, 23...
## 37 POLYGON ((227878 665244, 24...
## 38 POLYGON ((272040 672015, 28...
## 39 POLYGON ((233418 712863, 24...
## 40 POLYGON ((250189 678029, 25...
## 41 POLYGON ((247990 667816, 25...
## 42 POLYGON ((287329 691739, 29...
## 43 POLYGON ((286574 7e+05, 3e+...
## 44 POLYGON ((287710 665963, 29...
## 45 POLYGON ((311189 678784, 32...
## 46 POLYGON ((241202 652965, 24...
## 47 POLYGON ((257879 657031, 26...
## 48 POLYGON ((267205 662028, 26...
## 49 POLYGON ((251399 672324, 25...
## 50 POLYGON ((351626 732228, 33...
## 51 POLYGON ((274209 683508, 28...
## 52 POLYGON ((257360 676248, 25...
## 53 POLYGON ((252136 658209, 25...
## 54 POLYGON ((265911 681541, 27...
## 55 POLYGON ((314305 659828, 33...
## 56 POLYGON ((316714 617492, 31...

Analysis

Just before we jump into the analysis, I will create three additional resources:

  1. A Scotland boundary layer for annotating our maps
# Dissolve (union) over the district geometries in the lip_sf sf object to obtain  
# an outline (country) boundary for Scotland

sct_sf <- lip_sf %>%
  dplyr::mutate(country = "Scotland") %>%
  dplyr::summarise(geom = sf::st_union(geom),
                  .by = country)


base::print(sct_sf)
## Simple feature collection with 1 feature and 1 field
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: 95631 ymin: 530297 xmax: 454570 ymax: 1203008
## Projected CRS: OSGB36 / British National Grid
##    country                           geom
## 1 Scotland MULTIPOLYGON (((247093 5498...
  1. A list of districts labels to exclude from maps to reduce visual noise
# Create a vector of district names to exclude when labeling maps

exc_labels <- c("Eastwood",
                "Kilmarnock",
                "Monklands",
                "Motherwell",
                "Renfrew",
                "East Kilbride",
                "Cumbernauld",
                "Kirkcaldy",
                "West Lothian",
                "Inverclyde",
                "Strathkelvin",
                "Bearsden",
                "East Lothian",
                "Midlothian")
  1. A colour ramp with low, medium and high values to annotate ggplot2 scale elements
# Visualization colour palette

col_pal <- c("low" = RColorBrewer::brewer.pal(11, "RdYlBu")[11],
             "mid" = RColorBrewer::brewer.pal(11, "RdYlBu")[6],
             "high" = RColorBrewer::brewer.pal(11, "RdYlBu")[1])

# Create a colour ramp based on colour palette

rampColours <- grDevices::colorRampPalette(col_pal)

# Visualise the colour palette

graphics::par(mar = c(0, 0, 0, 0))

graphics::image(base::seq(1, 1000), 1, base::matrix(seq(1,1000), 1000,1), 
                col = rampColours(1000),
                pin = c(1, 5),
                axes = FALSE,
                ann = FALSE)

Observed (naïve) SIR

### Map observed SIR -----------------------------------------------------------

# Find the absolute maximum SIR on the log scale

max_log_sir <- base::as.integer(base::max(base::abs(base::log(lip_sf[lip_sf$obs_ca != 0, ]$obs_sir_est))) / 1) + 1

# Produce the raw SIR map ------------------------------------------------------

map_obs_sir <- ggplot2::ggplot() +
  
  # Add districts with SIR > 0
  
  ggplot2::geom_sf(data = lip_sf %>% dplyr::filter(obs_sir_est > 0),
                   mapping = ggplot2::aes(fill = obs_sir_est),
                   col = "grey50") +
  
  # Add districts with SIR = 0
  
  ggplot2::geom_sf(data = lip_sf %>% dplyr::filter(obs_sir_est == 0),
                   mapping = ggplot2::aes(alpha = base::factor("SIR = 0", ordered = TRUE)),
                   fill = "grey90",
                   colour = "grey50",
                   size = 0.1) +
  
  # Add SIR probability category
  
  ggplot2::geom_point(data = lip_sf %>% dplyr::filter(obs_sir_cat != ""),
                      mapping = ggplot2::aes(shape = obs_sir_cat,
                                             geometry = geom),
                      fill = "black",
                      stat = "sf_coordinates") +
  
  # Add Scotland boundary
  
  ggplot2::geom_sf(data = sct_sf,
                   fill = NA,
                   colour = "Black",
                   linewidth = 1) +
  
  # Add fill aesthetic gradient mapping
  
  ggplot2::scale_fill_gradient2("Observed SIR",
                                low = col_pal["low"], # blue
                                mid = col_pal["mid"], # yellow
                                high = col_pal["high"], # darkblue
                                midpoint = 0,
                                na.value = NA,
                                limits = c(base::exp(-max_log_sir), base::exp(max_log_sir)),
                                breaks = base::exp(base::seq(-max_log_sir, max_log_sir, 0.5)),
                                labels = base::format(base::round(exp(seq(-max_log_sir, max_log_sir, 0.5)), 2), nsmall = 2),
                                trans = "log") +
  
  ggplot2::scale_alpha_manual(values = c("SIR = 0" = 1)) +
  
  # Add shape aesthic mapping
  
  ggplot2::scale_shape_manual("Probability value",
                              values = c("++" = 24,
                                         "+" = 2,
                                         "-" = 6,
                                         "--" = 25),
                              breaks = c("++", "+", "-", "--"),
                              labels = c("++" = "SIR > 1, p < 0.01",
                                         "+" = "SIR > 1, p < 0.05",
                                         "-" = "SIR < 1, p < 0.05",
                                         "--" = "SIR < 1, p < 0.01")) +
  
  # Add code labels to identify districts
  
  # ggrepel::geom_text_repel(data = lip_sf %>% dplyr::filter(! dist_name %in% exc_labels),
  #                          inherit.aes = FALSE,
  #                          mapping = ggplot2::aes(label = dist_name,
  #                                                 geometry = geom),
  #                          stat = "sf_coordinates",
  #                          force = 0,
  #                          color = "white",
  #                          bg.color = "grey30",
  #                          bg.r = 0.1,
  #                          size = 9/.pt) +
  
  # Pretty up the legend
  
  ggplot2::guides(fill = ggplot2::guide_colourbar(frame.colour = "black", 
                                                  frame.linewidth = 0.25,
                                                  ticks.colour = "black",
                                                  ticks.linewidth = 0.25,
                                                  order = 1),
                  alpha = ggplot2::guide_legend(title = NULL, order = 2)) +
  
  # Pretty up the map
  
  ggplot2::theme_bw() + 
  
  ggplot2::theme(axis.title = ggplot2::element_blank(),
                 axis.text = ggplot2::element_blank(),
                 axis.ticks = ggplot2::element_blank(),
                 
                 legend.position = "inside",
                 legend.margin = ggplot2::margin(-3, 0, 0, 0),
                 legend.position.inside = c(0.15, 0.85),
                 
                 panel.grid = ggplot2::element_blank(),
                 
                 text = ggplot2::element_text(size = 12))

# Map relative standard errors for the observed SIR ----------------------------

map_obs_rse <- ggplot2::ggplot(data = lip_sf) +
  
  # Add relative standard errors for districts with SIR > 0
  
  # Add districts with SIR > 0
  
  ggplot2::geom_sf(data = lip_sf %>% dplyr::filter(obs_sir_est > 0),
                   mapping = ggplot2::aes(fill = obs_sir_rse),
                   col = "grey50") +
  
  # Add districts with SIR = 0
  
  ggplot2::geom_sf(data = lip_sf %>% dplyr::filter(obs_sir_est == 0),
                   mapping = ggplot2::aes(alpha = base::factor("SIR = 0", ordered = TRUE)),
                   fill = "grey90",
                   colour = "grey50",
                   size = 0.1) +
  
  # Add Scotland boundary
  
  ggplot2::geom_sf(data = sct_sf,
                   fill = NA,
                   colour = "Black",
                   linewidth = 1) +
  
  # Add code labels to identify districts
  
  ggrepel::geom_text_repel(data = (lip_sf %>%
                                     dplyr::filter(dist_name %in% c("Berwickshire",
                                                                    "Inverness",
                                                                    "Aberdeen",
                                                                    "Glasgow"))),
                           inherit.aes = FALSE,
                           mapping = ggplot2::aes(label = dist_name,
                                                  geometry = geom),
                           stat = "sf_coordinates",
                           force = 0,
                           color = "white",
                           bg.color = "grey30",
                           bg.r = 0.1,
                           size = 12/.pt) +
  
  # Add fill aesthetic gradient mapping
  
  ggplot2::scale_fill_gradient2("Relative standard error",
                                low = col_pal["low"], # blue
                                mid = col_pal["mid"], # yellow
                                high = col_pal["high"], # darkblue
                                midpoint = 0.5,
                                na.value = NA,
                                limits = c(0, 1),
                                breaks = base::seq(0, 1, 0.1),
                                labels = base::seq(0, 1, 0.1)) +
  
  ggplot2::scale_alpha_manual(values = c("SIR = 0" = 1)) +
  
  ggplot2::guides(fill = ggplot2::guide_colourbar(frame.colour = "black", 
                                                  frame.linewidth = 0.25,
                                                  ticks.colour = "black",
                                                  ticks.linewidth = 0.25,
                                                  order = 1),
                  alpha = ggplot2::guide_legend(title = NULL, order = 2)) +
  
  ggplot2::theme_bw() + 
  
  ggplot2::theme(axis.title = ggplot2::element_blank(),
                 axis.text = ggplot2::element_blank(),
                 axis.ticks = ggplot2::element_blank(),
                 
                 legend.position = "inside",
                 legend.margin = ggplot2::margin(-3, 0, 0, 0),
                 # legend.position.inside = c(0.15, 0.88),
                 legend.position.inside = c(0.18, 0.90),
                 legend.text = ggplot2::element_text(size = 10),
                 
                 panel.grid = ggplot2::element_blank(),
                 
                 text = ggplot2::element_text(size = 12))

# Map expected precision of SIR proportional to expected cancer cases -----------

map_exp_rse <- ggplot2::ggplot(data = lip_sf) +
  
  # Add relative standard errors for districts with SIR > 0
  
  # Add districts with E(R) > 0
  
  ggplot2::geom_sf(data = lip_sf, #  %>% dplyr::filter(obs_sir_est > 0),
                   mapping = ggplot2::aes(fill = exp_sir_rse),
                   col = "grey50") +
  
  # Add Scotland boundary
  
  ggplot2::geom_sf(data = sct_sf,
                   fill = NA,
                   colour = "Black",
                   linewidth = 1) +
  
  # Add fill aesthetic gradient mapping

  ggplot2::scale_fill_gradient2(base::expression("SE(R)" %prop% "1/E"), # "Expected precision of SIR",
                                low = col_pal["low"], # blue
                                mid = col_pal["mid"], # yellow
                                high = col_pal["high"], # darkblue
                                midpoint = 0.5,
                                na.value = NA,
                                limits = c(0, 1),
                                breaks = base::seq(0, 1, 0.1),
                                labels = base::seq(0, 1, 0.1)) +
  
  # ggplot2::scale_alpha_manual(values = c("SIR = 0" = 1)) +
  
  ggplot2::guides(fill = ggplot2::guide_colourbar(frame.colour = "black", 
                                                  frame.linewidth = 0.25,
                                                  ticks.colour = "black",
                                                  ticks.linewidth = 0.25,
                                                  order = 1),
                  alpha = ggplot2::guide_legend(title = NULL, order = 2)) +
  
  ggplot2::theme_bw() + 
  
  ggplot2::theme(axis.title = ggplot2::element_blank(),
                 axis.text = ggplot2::element_blank(),
                 axis.ticks = ggplot2::element_blank(),
                 
                 legend.position = "inside",
                 legend.margin = ggplot2::margin(-3, 0, 0, 0),
                 # legend.position.inside = c(0.15, 0.88),
                 legend.position.inside = c(0.13, 0.905),
                 legend.text = ggplot2::element_text(size = 10),
                 
                 panel.grid = ggplot2::element_blank(),
                 
                 text = ggplot2::element_text(size = 12))

## Output observed and BYM smoothed SIR for lip cancer risk --------------------

(map_obs_sir | map_obs_rse | map_exp_rse) +
  patchwork::plot_annotation(title = "Observed SIR estimates and p-values and observed and expected relative standard errors for male lip cancer in Scotland (1975-1980)", 
                             theme = theme(plot.title = element_text(hjust = 0.5)))

Queen adjacency matrix

Prior to conducting the BYM CAR analysis, we need to construct the queen adjacency matrix. This is easily using the spdep::poly2nb function.

### Create Queen adjacency (contiguity) list for each district -----------------

# The spdep::poly2nb function constructs a list of neighbours from a polygon object

adj_nb_list <- spdep::poly2nb(lip_sf, 
                              queen = TRUE, 
                              row.names = base::row.names(lip_sf))
## Warning in spdep::poly2nb(lip_sf, queen = TRUE, row.names = base::row.names(lip_sf)): some observations have no neighbours;
## if this seems unexpected, try increasing the snap argument.
## Warning in spdep::poly2nb(lip_sf, queen = TRUE, row.names = base::row.names(lip_sf)): neighbour object has 4 sub-graphs;
## if this sub-graph count seems unexpected, try increasing the snap argument.
base::print(adj_nb_list)
## Neighbour list object:
## Number of regions: 56 
## Number of nonzero links: 234 
## Percentage nonzero weights: 7.461735 
## Average number of links: 4.178571 
## 3 regions with no links:
## 6, 8, 11
## 4 disjoint connected subgraphs
# View adjacency list structure

utils::head(adj_nb_list)
## [[1]]
## [1]  5  9 19
## 
## [[2]]
## [1]  7 10
## 
## [[3]]
## [1] 12
## 
## [[4]]
## [1] 18 20 28
## 
## [[5]]
## [1]  1 12 19
## 
## [[6]]
## [1] 0

The warning message is telling us three districts (districts 6, 8 and 11) have no neighbours, which is reasonable as there are three island areas (districts), and that one has (district 4) has disjoint connected subgraphs. This likely means the area is sharing multiple borders (edges) with the same neighbour. This can occur when there a “slivers” — small gaps — in your spatial data between bordering spatial units. Given the map available for Scotland looks like a five-year old has cut it out of coloured paper with blunt craft scissors and from memory, this almost certainly likely. We can check these warnings are OK via some additional maps.

# Provide district map for reference -------------------------------------------

adj_dist_map <- ggplot2::ggplot() +
  
  # Add districts with SIR > 0
  
  ggplot2::geom_sf(data = lip_sf,
                   fill = NA,
                   col = "black",
                   linewidth = 0.25) +
  
  # Add Scotland boundary
  
  ggplot2::geom_sf(data = sct_sf,
                   fill = NA,
                   colour = "Black",
                   linewidth = 1) +
  
  # Add code labels to identify districts
  
  ggplot2::geom_text(data = lip_sf,
                           inherit.aes = FALSE,
                           mapping = ggplot2::aes(label = dist_code,
                                                  geometry = geom),
                           stat = "sf_coordinates",
                           color = "black",
                           size = 12/.pt) +
  
  ggplot2::theme_bw() + 
  
  ggplot2::theme(axis.title = ggplot2::element_blank(),
                 axis.text = ggplot2::element_blank(),
                 axis.ticks = ggplot2::element_blank(),
                 
                 legend.position = "inside",
                 legend.margin = ggplot2::margin(-3, 0, 0, 0),
                 # legend.position.inside = c(0.15, 0.88),
                 legend.position.inside = c(0.13, 0.905),
                 legend.text = ggplot2::element_text(size = 10),
                 
                 panel.grid = ggplot2::element_blank(),
                 
                 text = ggplot2::element_text(size = 12))

# Map some neighbours ----------------------------------------------------------

adj_nb_map <- ggplot2::ggplot() +
  
  
  # Add districts
  
  ggplot2::geom_sf(data = lip_sf,
                   colour = "grey50",
                   fill = NA,
                   linewidth = 0.1) +
  
  # Areas of interest
  
  #  4 = Berwickshire
  # 19 = Inverness
  # 22 = Aberdeen
  # 49 = Glasgow
  
  ggplot2::geom_sf(data = lip_sf %>% filter(row.names(.) %in% c(4, 19, 22, 49)),
                   mapping = ggplot2::aes(fill = "Analysis district"),
                   colour = "black",
                   linewidth = 0.1) +
  
  # Neighbours of areas of interest
  
  ggplot2::geom_sf(data = lip_sf %>% filter(row.names(.) %in% unlist(adj_nb_list[c(4, 19, 22, 49)])),
                   mapping = aes(fill = "Queen neighbours"),
                   colour = "black",
                   linewidth = 0.1) +
  
  # Add Scotland boundary
  
  ggplot2::geom_sf(data = sct_sf,
                   fill = NA,
                   colour = "Black",
                   linewidth = 1) +
  
  # Add code labels to identify districts
  
  ggrepel::geom_text_repel(data = (lip_sf %>%
                                     dplyr::filter(dist_name %in% c("Berwickshire",
                                                                    "Inverness",
                                                                    "Aberdeen",
                                                                    "Glasgow"))),
                           inherit.aes = FALSE,
                           mapping = ggplot2::aes(label = dist_name,
                                                  geometry = geom),
                           stat = "sf_coordinates",
                           force = 0,
                           color = "white",
                           bg.color = "grey30",
                           bg.r = 0.1,
                           size = 12/.pt) +
  
  # Add fill aesthetic gradient mapping
  
  ggplot2::scale_fill_manual("Adjacency examples",
                             breaks = c("Analysis district",
                                        "Queen neighbours"),
                             values = c(rgb(230, 70, 38, maxColorValue = 255),
                                        rgb(255, 212, 102, maxColorValue = 255))) +
  
  # Add X and Y coordinate labels
  
  ggplot2::theme_bw() +
  
  ggplot2::theme(axis.title = ggplot2::element_blank(),
                 axis.text = ggplot2::element_blank(),
                 axis.ticks = ggplot2::element_blank(),
                 
                 legend.position = "inside",
                 legend.margin = ggplot2::margin(0, 0, 0, 0),
                 legend.position.inside = c(0.2, 0.93),
                 
                 panel.grid = ggplot2::element_blank(),
                 
                 text = ggplot2::element_text(size = 12))

# Plot neighbours connectivity graph -------------------------------------------

# Genereate connectivity arcs between spatial units and their neighbours

# From: https://mbjoseph.github.io/posts/2018-12-27-plotting-spatial-neighbors-in-ggplot2/

# The spdep::nb2lines function creates linestring geometries linking the centroids
# of neighbouring districts

adj_nb_arc <- spdep::nb2lines(adj_nb_list,
                              coords = st_centroid(st_geometry(lip_sf)))

# Calculate the number of neighbours for each district by summarising the length
# of each element in the adj_nb_list

adj_nb_num <- lapply(adj_nb_list, length) %>%
  do.call(rbind, .) %>%
  as.data.frame() %>%
  setNames("neighbours")

## Map adjacency marks and symbolise by number of neighbours -------------------

adj_con_map <- ggplot() +
  
  # Add districts
  
  geom_sf(data = lip_sf %>% bind_cols(adj_nb_num),
          aes(fill = neighbours),
          colour = "grey50",
          linewidth = 0.1,
          alpha = 0.75) +
  
  # Add neighbour connectivity arcs
  
  geom_sf(data = adj_nb_arc,
          colour = "black",
          linewidth = 0.1) +
  
  # Add district centroids
  
  geom_sf(data = st_centroid(st_geometry(lip_sf)),
          shape = 16,
          colour = "black",
          size = 2.75) +
  
  # Add code labels to identify districts
  
  ggrepel::geom_text_repel(data = lip_sf %>% dplyr::filter(! dist_name %in% exc_labels),
                           inherit.aes = FALSE,
                           mapping = ggplot2::aes(label = dist_name,
                                                  geometry = geom),
                           stat = "sf_coordinates",
                           force = 0,
                           color = "white",
                           bg.color = "grey30",
                           bg.r = 0.1,
                           size = 12/.pt) +
  
  # Add fill aesthetic gradient mapping
  
  scale_fill_gradient("Neighbours",
                      low = "lightyellow",
                      high = "darkred",
                      limits = c(0, 11),
                      breaks = seq(0, 11, 1),
                      # labels = c("1", "", "", "", "", "6", "", "", "", "", "", "12"),
                      guide = guide_colorbar(frame.colour = "black", 
                                             frame.linewidth = 0.25,
                                             ticks.colour = "black",
                                             ticks.linewidth = 0.25)) +
  
  theme_bw() +
  
  theme(axis.title = ggplot2::element_blank(),
        axis.text = ggplot2::element_blank(),
        axis.ticks = ggplot2::element_blank(),
        
        legend.position = "inside",
        legend.margin = ggplot2::margin(0, 0, 0, 0),
        legend.position.inside = c(0.15, 0.90),
        
        panel.grid = ggplot2::element_blank(),
        
        text = ggplot2::element_text(size = 12))

## Output adjacency maps -------------------------------------------------------

(adj_dist_map | adj_nb_map | adj_con_map) +
  patchwork::plot_annotation(title = "Spatial neighbours and links maps for Scottish administrative districts", 
                             theme = theme(plot.title = element_text(hjust = 0.5)))

Based on these maps, we can be confident the three districts without neighbours are island areas (Western Isles, Orkney and Shetland) and that district 4 (Berwickshire) is connected to the correct number of neighbours (n=3). We can now convert the spdep adjacency matrix to WinBUGS weight matrix format, which is required for fitting BYM CAR models in nimble.

### Output adjacency matrix in WinBUGS format for use in BYM models ------------

# The spdep::nb2WB function can be used to make WinBUGS neighbours list 

adj_nb_wgt <- spdep::nb2WB(nb = adj_nb_list)

# View WinBUIGS adjacency list

base::print(adj_nb_wgt)
## $adj
##   [1]  5  9 19  7 10 12 18 20 28  1 12 19  2 10 13 16 17  1 17 19 23 29  2  7 16 22  3  5  7 17 19 31 32 35 25 29  7 10 17 21 22 29  7  9 13 16 19 29  4 20 28 33 55 56  1
##  [56]  5  9 13 17  4 18 56 16 29 50 10 16  9 29 34 39 27 30 31 44 47 48 55 56 15 26 29 25 29 43 24 31 32 56  4 18 33 45  9 15 16 17 21 23 25 26 34 43 50 24 38 42 44 45 55
## [111] 14 24 27 32 35 46 47 14 27 31 18 28 45 55 23 29 39 40 42 43 51 52 54 14 31 37 46 37 41 35 36 41 46 30 42 44 49 51 54 23 34 40 34 39 49 52 36 37 46 49 53 30 34 38 43
## [166] 51 26 29 34 42 24 30 38 48 49 28 30 33 55 31 35 37 41 47 53 24 31 46 48 49 53 24 44 47 49 38 40 41 44 47 48 52 53 54 21 29 34 38 42 54 34 40 49 54 41 46 47 49 34 38
## [221] 49 51 52 18 24 30 33 45 56 18 20 24 27 55
## 
## $weights
##   [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
##  [83] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## [165] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## 
## $num
##  [1]  3  2  1  3  3  0  5  0  5  4  0  2  3  3  2  6  6  6  5  3  3  2  4  8  3  3  4  4 11  6  7  3  4  9  4  2  4  6  3  4  5  5  4  5  4  6  6  4  9  2  4  4  4  5  6
## [56]  5
# The *adj* vector defines the district indexes for the neighbours of the ith
# analysis unit; the *weights* vector indicates the weight assigned to each
# neighbour when calculating the conditional autoregression spatial term
# in the BYM model; and *num* indicates how many of the neighbours in *adj*
# border the ith analysis unit. For example, the first element of *num* indicates
# that the district of Skye-Lochalsh (row 1 in *lip_sf*) has three neighbours, 
# which *adj* indicates correspond to row indexes 5, 9 and 19 (Ross-Cromarty,
# Lochaber and Inverness districts) in *lip_sf*, and are assigned weights of 1, 
# 1 and 1 when calculating the CAR spatial term for Skye-Lochalsh.

BYM CAR disease mapping model

We now have everything necessary to run a BYM CAR disease mapping model. All that is left is to format the data in the way nimble expects it to be, write and compile our model, and then run and summarise its output.

### Assemble objects needed to run a BYM disease model -------------------------

## Obtain the number of districts ----------------------------------------------

N <- dim(lip_sf)[1]

## Format SIR data for NIMBLE in a list ----------------------------------------

bym_data <- base::list(obs = lip_sf$obs_ca)               # Observed lip cancer cases

## List constants required by NIMBLE to fit BYM model --------------------------

bym_consts <-base::list(N = N,                          # Number of districts 
                        
                        exp = lip_sf$exp_ca,               # Expected lip cancer cases
                        
                        # Adjacency matrix values used to specify CAR distribution
                        
                        L = length(adj_nb_wgt$weights),  # Total number of neighbours        
                        adj = adj_nb_wgt$adj,            # Vector of neighbours for each ditrict                            
                        num = adj_nb_wgt$num,            # Vector of neighbour counts for each district
                        weights = adj_nb_wgt$weights)    # Weight for each neighbour (all 1 for a queen matrix

base::print(bym_consts)
## $N
## [1] 56
## 
## $exp
##  [1]  1.38  8.66  3.04  2.53  4.26  2.40  8.11  2.30  1.98  6.63  4.40  1.79  1.08  3.31  7.84  4.55  1.07  4.18  5.53  4.44 10.46 22.67  8.77  5.62 15.47 12.49  6.04
## [28]  8.96 14.37 10.20  4.75  2.88  7.03  8.53 12.32 10.10 12.68  9.35  7.20  5.27 18.76 15.78  4.32 14.63 50.72  8.20  5.59  9.34 88.66 19.62  3.44  3.62  5.74  7.03
## [55]  4.16  1.76
## attr(,"label")
## [1] "Expected male lip cancer cases (1975-1980)"
## 
## $L
## [1] 234
## 
## $adj
##   [1]  5  9 19  7 10 12 18 20 28  1 12 19  2 10 13 16 17  1 17 19 23 29  2  7 16 22  3  5  7 17 19 31 32 35 25 29  7 10 17 21 22 29  7  9 13 16 19 29  4 20 28 33 55 56  1
##  [56]  5  9 13 17  4 18 56 16 29 50 10 16  9 29 34 39 27 30 31 44 47 48 55 56 15 26 29 25 29 43 24 31 32 56  4 18 33 45  9 15 16 17 21 23 25 26 34 43 50 24 38 42 44 45 55
## [111] 14 24 27 32 35 46 47 14 27 31 18 28 45 55 23 29 39 40 42 43 51 52 54 14 31 37 46 37 41 35 36 41 46 30 42 44 49 51 54 23 34 40 34 39 49 52 36 37 46 49 53 30 34 38 43
## [166] 51 26 29 34 42 24 30 38 48 49 28 30 33 55 31 35 37 41 47 53 24 31 46 48 49 53 24 44 47 49 38 40 41 44 47 48 52 53 54 21 29 34 38 42 54 34 40 49 54 41 46 47 49 34 38
## [221] 49 51 52 18 24 30 33 45 56 18 20 24 27 55
## 
## $num
##  [1]  3  2  1  3  3  0  5  0  5  4  0  2  3  3  2  6  6  6  5  3  3  2  4  8  3  3  4  4 11  6  7  3  4  9  4  2  4  6  3  4  5  5  4  5  4  6  6  4  9  2  4  4  4  5  6
## [56]  5
## 
## $weights
##   [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
##  [83] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## [165] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## Write the model specification -----------------------------------------------

# NOTE: Don't use R namespaces as models are run by the nimble C++ compiler

bym_code <- nimble::nimbleCode(
  {
    for (i in 1:N){
      
      # Poisson likelihood for observed counts
      
      obs[i] ~ dpois(lambda[i]) 
      log(lambda[i]) <- alpha + s[i] + u[i] + log(exp[i])
      
      # Prior for the area-specific unstructured random effect
      
      u[i] ~ dnorm(0, tau = tau.u)    
      
      # Smoothed area-specific SIR
      
      smoothed.sir[i] <- exp(alpha + s[i] + u[i])
      
      # Overall residual area-specific cancer risk above or below the Scottish average
      
      residual.sir[i] <- exp(s[i] + u[i])
      
      # Residual area-specific cancer risk due to unobserved and spatially structured factors (s)
      
      residual.sir.s[i] <- exp(s[i])
      
      # Residual area-specific lip cancer risk due to unobserved and spatially unstructured factors (u)
      
      residual.sir.u[i] <- exp(u[i])
      
      # Posterior probabilities for residual risk - is the SIR for the ith district higher or lower than 1
      
      residual.sir.gt1[i] <- 1 - step(1 - residual.sir[i]) # Posterior probability that SIR > 1
      residual.sir.lt1[i] <- 1 - step(residual.sir[i] - 1) # Posterior probability that SIR < 1                         
    } 
    
    # Prior for the area-specific spatially structured random effect (ICAR)
    
    s[1:N] ~ dcar_normal(adj[1:L],
                         weights[1:L],
                         num[1:N],
                         tau.s,
                         zero_mean = 1)
    
    # Vague uniform prior for intercept
    
    alpha ~ dflat()                                       
    
    # Overall SIR for the study region (lip cancer risk common to all areas)
    
    overall.sir <- exp(alpha)                                
    
    # Hyperprior distribution on inverse variance (precision) for the unstructured variance component (u)
    
    tau.u ~ dgamma(1, 0.01)                            
    
    # Variance of u (unstructured variance component)
    
    sigma2.u <- 1/tau.u                                   
    
    # Hyperprior distribution on inverse variance (precision) for the spatially structured variance component (s)
    
    tau.s ~ dgamma(1, 0.01)                              
    
    # variance of s (spatial variance component)
    
    sigma2.s <- 1/tau.s
    
  }
)

base::print(bym_code)
## {
##     for (i in 1:N) {
##         obs[i] ~ dpois(lambda[i])
##         log(lambda[i]) <- alpha + s[i] + u[i] + log(exp[i])
##         u[i] ~ dnorm(0, tau = tau.u)
##         smoothed.sir[i] <- exp(alpha + s[i] + u[i])
##         residual.sir[i] <- exp(s[i] + u[i])
##         residual.sir.s[i] <- exp(s[i])
##         residual.sir.u[i] <- exp(u[i])
##         residual.sir.gt1[i] <- 1 - step(1 - residual.sir[i])
##         residual.sir.lt1[i] <- 1 - step(residual.sir[i] - 1)
##     }
##     s[1:N] ~ dcar_normal(adj[1:L], weights[1:L], num[1:N], tau.s, 
##         zero_mean = 1)
##     alpha ~ dflat()
##     overall.sir <- exp(alpha)
##     tau.u ~ dgamma(1, 0.01)
##     sigma2.u <- 1/tau.u
##     tau.s ~ dgamma(1, 0.01)
##     sigma2.s <- 1/tau.s
## }
## Specify initial values for nodes as a data list -----------------------------

# alpha = intercept
# u     = prior for unstructured random effect
# tau.u = hyperprior for the precision of u
# s     = prior for structured random effect
# tau.s = hyperprior for the precision of s

bym_inits <- list(list(alpha = 0.01,                              # MCMC chain 1 
                       u = base::rep(0.01, times = N), 
                       tau.u = 10,
                       s = base::rep(0.01, times = N),
                       tau.s = 10),
                  list(alpha = 0.5,                               # MCMC chain 2
                       u = base::rep(-0.01, times = N),
                       tau.u = 1,
                       s = base::rep(-0.01, times = N),
                       tau.s = 1))

base::print(bym_inits)
## [[1]]
## [[1]]$alpha
## [1] 0.01
## 
## [[1]]$u
##  [1] 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01
## [34] 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01
## 
## [[1]]$tau.u
## [1] 10
## 
## [[1]]$s
##  [1] 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01
## [34] 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01
## 
## [[1]]$tau.s
## [1] 10
## 
## 
## [[2]]
## [[2]]$alpha
## [1] 0.5
## 
## [[2]]$u
##  [1] -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01
## [28] -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01
## [55] -0.01 -0.01
## 
## [[2]]$tau.u
## [1] 1
## 
## [[2]]$s
##  [1] -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01
## [28] -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01 -0.01
## [55] -0.01 -0.01
## 
## [[2]]$tau.s
## [1] 1
## Select parameters (nodes) to monitor ----------------------------------------

bym_params <- c("alpha",
                "u",
                "s",
                "sigma2.s",
                "sigma2.u",
                "overall.sir",
                "residual.sir",
                "residual.sir.s",
                "residual.sir.u",
                "smoothed.sir",
                "residual.sir.gt1",
                "residual.sir.lt1")

print(bym_params)
##  [1] "alpha"            "u"                "s"                "sigma2.s"         "sigma2.u"         "overall.sir"      "residual.sir"     "residual.sir.s"  
##  [9] "residual.sir.u"   "smoothed.sir"     "residual.sir.gt1" "residual.sir.lt1"
## Specify the MCMC sampler settings -------------------------------------------

n_chains <- 2             # Number of MCMC chains to run  
n_burnin <- 50000         # Number of iterations to use as model burn-in
n_iter <- n_burnin * 2    # Number of iterations per chain
n_thin <- 1              # Thinning interval for chain, i.e., keep every nth sample

# Burn-in samples per chain (n = 2) - used to converge model

(n_burnin / n_thin)                # 5000 samples used to burn the model in
## [1] 50000
# Inference samples per chain (n = 2)

((n_iter - n_burnin) / n_thin)     # 5000 samples from the posterior distribution summarised for inference
## [1] 50000
### Fit the model --------------------------------------------------------------

# The nimble showCompilerOutput and nimbleMCMC options are set to TRUE for
# demonstration purposes only. You can exclude these options if you prefer

nimbleOptions(showCompilerOutput = TRUE)
bym_samples <- nimble::nimbleMCMC(code = bym_code,
                                  data = bym_data,
                                  constants = bym_consts, 
                                  inits = bym_inits,
                                  monitors = bym_params,
                                  niter = n_iter,
                                  nburnin = n_burnin,
                                  thin = n_thin, 
                                  nchains = n_chains, 
                                  setSeed = c(9, 10),              # Seed for randome number generator - important for reproducibility - need one seed per chain  
                                  progressBar = TRUE,
                                  samplesAsCodaMCMC = TRUE, 
                                  summary = TRUE, 
                                  WAIC = TRUE)
## Defining model
## Building model
## Setting data and initial values
## Running calculate on model
##   [Note] Any error reports that follow may simply reflect missing values in model variables.
## Checking model sizes and dimensions
## Checking model calculations
## Compiling
##   [Note] This may take a minute.
##   [Note] On some systems there may be some compiler warnings that can be safely ignored.
## g++ -std=gnu++17  -I"C:/Software/R/R-43~1.3/include" -DNDEBUG -DR_NO_REMAP -I"C:\Software\R\R-4.3.3\library\nimble\include" -I"" -DEIGEN_MPL2_ONLY=1 -Wno-misleading-indentation -Wno-ignored-attributes -Wno-deprecated-declarations -std=c++11    -I"C:/Software/R/rtools43/x86_64-w64-mingw32.static.posix/include"     -O2 -Wall  -mfpmath=sse -msse2 -mstackrealign  -c dynamicRegistrations_04_30_14_18_05.cpp -o dynamicRegistrations_04_30_14_18_05.o
## g++ -std=gnu++17 -shared -s -static-libgcc -o dynamicRegistrations_04_30_14_18_05.dll tmp.def dynamicRegistrations_04_30_14_18_05.o -LC:\Software\R\R-4.3.3\library\nimble\CppCode -lnimble_x64 -lRlapack -lRblas -LC:/Software/R/rtools43/x86_64-w64-mingw32.static.posix/lib/x64 -LC:/Software/R/rtools43/x86_64-w64-mingw32.static.posix/lib -LC:/Software/R/R-43~1.3/bin/x64 -lR
## using C++ compiler: 'G__~1.EXE (GCC) 12.2.0'
## g++ -std=gnu++17  -I"C:/Software/R/R-43~1.3/include" -DNDEBUG -DR_NO_REMAP -I"C:\Software\R\R-4.3.3\library\nimble\include" -I"" -DEIGEN_MPL2_ONLY=1 -Wno-misleading-indentation -Wno-ignored-attributes -Wno-deprecated-declarations -std=c++11    -I"C:/Software/R/rtools43/x86_64-w64-mingw32.static.posix/include"     -O2 -Wall  -mfpmath=sse -msse2 -mstackrealign  -c P_1_code_MID_1.cpp -o P_1_code_MID_1.o
## g++ -std=gnu++17  -I"C:/Software/R/R-43~1.3/include" -DNDEBUG -DR_NO_REMAP -I"C:\Software\R\R-4.3.3\library\nimble\include" -I"" -DEIGEN_MPL2_ONLY=1 -Wno-misleading-indentation -Wno-ignored-attributes -Wno-deprecated-declarations -std=c++11    -I"C:/Software/R/rtools43/x86_64-w64-mingw32.static.posix/include"     -O2 -Wall  -mfpmath=sse -msse2 -mstackrealign  -c P_1_code_MID_1_nfCode.cpp -o P_1_code_MID_1_nfCode.o
## g++ -std=gnu++17 -shared -s -static-libgcc -o P_1_code_MID_1_04_30_14_18_05.dll tmp.def P_1_code_MID_1.o P_1_code_MID_1_nfCode.o -LC:\Software\R\R-4.3.3\library\nimble\CppCode -lnimble_x64 -lRlapack -lRblas -LC:/Software/R/rtools43/x86_64-w64-mingw32.static.posix/lib/x64 -LC:/Software/R/rtools43/x86_64-w64-mingw32.static.posix/lib -LC:/Software/R/R-43~1.3/bin/x64 -lR
## using C++ compiler: 'G__~1.EXE (GCC) 12.2.0'
## g++ -std=gnu++17  -I"C:/Software/R/R-43~1.3/include" -DNDEBUG -DR_NO_REMAP -I"C:\Software\R\R-4.3.3\library\nimble\include" -I"" -DEIGEN_MPL2_ONLY=1 -Wno-misleading-indentation -Wno-ignored-attributes -Wno-deprecated-declarations -std=c++11    -I"C:/Software/R/rtools43/x86_64-w64-mingw32.static.posix/include"     -O2 -Wall  -mfpmath=sse -msse2 -mstackrealign  -c P_1_MCMC.cpp -o P_1_MCMC.o
## g++ -std=gnu++17  -I"C:/Software/R/R-43~1.3/include" -DNDEBUG -DR_NO_REMAP -I"C:\Software\R\R-4.3.3\library\nimble\include" -I"" -DEIGEN_MPL2_ONLY=1 -Wno-misleading-indentation -Wno-ignored-attributes -Wno-deprecated-declarations -std=c++11    -I"C:/Software/R/rtools43/x86_64-w64-mingw32.static.posix/include"     -O2 -Wall  -mfpmath=sse -msse2 -mstackrealign  -c P_1_code_MID_1.cpp -o P_1_code_MID_1.o
## g++ -std=gnu++17 -shared -s -static-libgcc -o P_1_MCMC_04_30_14_18_29.dll tmp.def P_1_MCMC.o P_1_code_MID_1.o -LC:\Software\R\R-4.3.3\library\nimble\CppCode -lnimble_x64 -lRlapack -lRblas -LC:/Software/R/rtools43/x86_64-w64-mingw32.static.posix/lib/x64 -LC:/Software/R/rtools43/x86_64-w64-mingw32.static.posix/lib -LC:/Software/R/R-43~1.3/bin/x64 -lR
## using C++ compiler: 'G__~1.EXE (GCC) 12.2.0'
## In file included from C:\Software\R\R-4.3.3\library\nimble\include/nimble/nimbleEigen.h:162,
##                  from C:\Software\R\R-4.3.3\library\nimble\include/nimble/EigenTypedefs.h:33,
##                  from P_1_MCMC.cpp:8:
## C:\Software\R\R-4.3.3\library\nimble\include/nimble/nimbleEigenNimArr.h: In instantiation of 'void assignVectorToNimArr(NimArrOutput&, const VectorInput&) [with NimArrOutput = NimArr<1, int>; VectorInput = std::vector<int>]':
## C:\Software\R\R-4.3.3\library\nimble\include/nimble/nimbleEigenNimArr.h:339:56:   required from 'void setWhich(NimArrOutput&, const DerivedBool&) [with NimArrOutput = NimArr<1, int>; DerivedBool = Eigen::CwiseBinaryOp<Eigen::internal::scalar_cmp_op<double, double, Eigen::internal::cmp_LT>, const Eigen::CwiseNullaryOp<Eigen::internal::scalar_constant_op<double>, Eigen::Array<double, -1, -1, 1, -1, -1> >, const Eigen::ArrayWrapper<const Eigen::CwiseBinaryOp<Eigen::internal::scalar_quotient_op<double, double>, const Eigen::Transpose<Eigen::Block<Eigen::Map<Eigen::Matrix<double, -1, -1>, 0, Eigen::Stride<0, 0> >, -1, -1, false> >, const Eigen::CwiseNullaryOp<Eigen::internal::scalar_constant_op<double>, const Eigen::Matrix<double, -1, -1, 1, -1, -1> > > > >]'
## P_1_MCMC.cpp:1265:10:   required from here
## C:\Software\R\R-4.3.3\library\nimble\include/nimble/nimbleEigenNimArr.h:318:22: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long long unsigned int'} [-Wsign-compare]
##   318 |     if(output.size() != input.size()) {
##       |        ~~~~~~~~~~~~~~^~~~~~~~~~~~~~~
## C:\Software\R\R-4.3.3\library\nimble\include/nimble/nimbleEigenNimArr.h:322:22: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long long unsigned int'} [-Wsign-compare]
##   322 |     for(int i = 0; i < input.size(); i++) output[i] = input[i];
##       |                    ~~^~~~~~~~~~~~~~
## C:\Software\R\R-4.3.3\library\nimble\include/nimble/nimbleEigenNimArr.h:325:22: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long long unsigned int'} [-Wsign-compare]
##   325 |     for(int i = 0; i < input.size(); i++) output.valueNoMap(i) = input[i];
##       |                    ~~^~~~~~~~~~~~~~
## In file included from C:\Software\R\R-4.3.3\library\nimble\include/nimble/EigenTypedefs.h:28:
## In destructor 'virtual pointedToBase::~pointedToBase()',
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:144:14,
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:132:8,
##     inlined from 'nimSmartPtr<T>::~nimSmartPtr() [with T = waicNimbleList]' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:116:29:
## C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:147:29: warning: 'void operator delete(void*)' called on pointer '*this.nimSmartPtr<waicNimbleList>::realPtr' with nonzero offset 56 [-Wfree-nonheap-object]
##   147 |   virtual ~pointedToBase() {};
##       |                             ^
## In destructor 'virtual pointedToBase::~pointedToBase()',
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:144:14,
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:132:8,
##     inlined from 'nimSmartPtr<T>::~nimSmartPtr() [with T = waicDetailsNimbleList]' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:116:29:
## C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:147:29: warning: 'void operator delete(void*)' called on pointer '*this.nimSmartPtr<waicDetailsNimbleList>::realPtr' with nonzero offset 56 [-Wfree-nonheap-object]
##   147 |   virtual ~pointedToBase() {};
##       |                             ^
## In destructor 'virtual pointedToBase::~pointedToBase()',
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:144:14,
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:132:8,
##     inlined from 'nimSmartPtr<T>::~nimSmartPtr() [with T = waicNimbleList]' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:116:29,
##     inlined from 'nimSmartPtr<T>::~nimSmartPtr() [with T = waicNimbleList]' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:117:3:
## C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:147:29: warning: 'void operator delete(void*)' called on pointer '*this.nimSmartPtr<waicNimbleList>::realPtr' with nonzero offset 56 [-Wfree-nonheap-object]
##   147 |   virtual ~pointedToBase() {};
##       |                             ^
## In destructor 'virtual pointedToBase::~pointedToBase()',
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:144:14,
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:132:8,
##     inlined from 'nimSmartPtr<T>::~nimSmartPtr() [with T = waicDetailsNimbleList]' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:116:29,
##     inlined from 'nimSmartPtr<T>::~nimSmartPtr() [with T = waicDetailsNimbleList]' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:117:3:
## C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:147:29: warning: 'void operator delete(void*)' called on pointer '*this.nimSmartPtr<waicDetailsNimbleList>::realPtr' with nonzero offset 56 [-Wfree-nonheap-object]
##   147 |   virtual ~pointedToBase() {};
##       |                             ^
## In destructor 'virtual pointedToBase::~pointedToBase()',
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:144:14,
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:132:8,
##     inlined from 'void nimSmartPtr<T>::setPtrFromT(T*&) [with T = waicNimbleList]' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:55:39,
##     inlined from 'void nimSmartPtr<T>::setPtrFromVoidPtr(void*&) [with T = waicNimbleList]' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:64:16:
## C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:147:29: warning: 'void operator delete(void*)' called on pointer '*this.nimSmartPtr<waicNimbleList>::realPtr' with nonzero offset 56 [-Wfree-nonheap-object]
##   147 |   virtual ~pointedToBase() {};
##       |                             ^
## In destructor 'virtual pointedToBase::~pointedToBase()',
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:144:14,
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:132:8,
##     inlined from 'void nimSmartPtr<T>::setPtrFromT(T*&) [with T = waicDetailsNimbleList]' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:55:39,
##     inlined from 'void nimSmartPtr<T>::setPtrFromVoidPtr(void*&) [with T = waicDetailsNimbleList]' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:64:16:
## C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:147:29: warning: 'void operator delete(void*)' called on pointer '*this.nimSmartPtr<waicDetailsNimbleList>::realPtr' with nonzero offset 56 [-Wfree-nonheap-object]
##   147 |   virtual ~pointedToBase() {};
##       |                             ^
## In destructor 'virtual pointedToBase::~pointedToBase()',
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:144:14,
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:132:8,
##     inlined from 'void nimSmartPtr<T>::setPtr(const nimSmartPtr<T>&) [with T = waicNimbleList]' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:49:39,
##     inlined from 'nimSmartPtr<T>& nimSmartPtr<T>::operator=(const nimSmartPtr<T>&) [with T = waicNimbleList]' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:79:11,
##     inlined from 'virtual nimSmartPtr<waicNimbleList> waicClass::calculateWAIC(int, double)' at P_1_MCMC.cpp:1360:17:
## C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:147:29: warning: 'void operator delete(void*)' called on pointer '*<return-value>.nimSmartPtr<waicNimbleList>::realPtr' with nonzero offset 56 [-Wfree-nonheap-object]
##   147 |   virtual ~pointedToBase() {};
##       |                             ^
## In destructor 'virtual pointedToBase::~pointedToBase()',
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:144:14,
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:132:8,
##     inlined from 'nimSmartPtr<T>::~nimSmartPtr() [with T = waicNimbleList]' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:116:29,
##     inlined from 'virtual nimSmartPtr<waicNimbleList> waicClass::calculateWAIC(int, double)' at P_1_MCMC.cpp:1360:17:
## C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:147:29: warning: 'void operator delete(void*)' called on pointer '<unknown>' with nonzero offset 56 [-Wfree-nonheap-object]
##   147 |   virtual ~pointedToBase() {};
##       |                             ^
## P_1_MCMC.cpp: In member function 'virtual nimSmartPtr<waicNimbleList> waicClass::calculateWAIC(int, double)':
## P_1_MCMC.cpp:1360:17: note: returned from 'void* operator new(std::size_t)'
##  1360 | Interm_84 = new waicNimbleList;
##       |                 ^~~~~~~~~~~~~~
## In destructor 'virtual pointedToBase::~pointedToBase()',
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:144:14,
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:132:8,
##     inlined from 'nimSmartPtr<T>::~nimSmartPtr() [with T = waicNimbleList]' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:116:29,
##     inlined from 'SEXPREC* CALL_waicClass_get(SEXP)' at P_1_MCMC.cpp:1476:79:
## C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:147:29: warning: 'void operator delete(void*)' called on pointer '<anonymous>.nimSmartPtr<waicNimbleList>::realPtr' with nonzero offset 56 [-Wfree-nonheap-object]
##   147 |   virtual ~pointedToBase() {};
##       |                             ^
## In destructor 'virtual pointedToBase::~pointedToBase()',
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:144:14,
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:132:8,
##     inlined from 'nimSmartPtr<T>::~nimSmartPtr() [with T = waicDetailsNimbleList]' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:116:29,
##     inlined from 'SEXPREC* CALL_waicClass_getDetails(SEXP, SEXP)' at P_1_MCMC.cpp:1494:86:
## C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:147:29: warning: 'void operator delete(void*)' called on pointer '<anonymous>.nimSmartPtr<waicDetailsNimbleList>::realPtr' with nonzero offset 56 [-Wfree-nonheap-object]
##   147 |   virtual ~pointedToBase() {};
##       |                             ^
## In destructor 'virtual pointedToBase::~pointedToBase()',
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:144:14,
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:132:8,
##     inlined from 'nimSmartPtr<T>::~nimSmartPtr() [with T = waicNimbleList]' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:116:29,
##     inlined from 'SEXPREC* CALL_waicClass_calculateWAIC(SEXP, SEXP, SEXP)' at P_1_MCMC.cpp:1523:89:
## C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:147:29: warning: 'void operator delete(void*)' called on pointer '<anonymous>.nimSmartPtr<waicNimbleList>::realPtr' with nonzero offset 56 [-Wfree-nonheap-object]
##   147 |   virtual ~pointedToBase() {};
##       |                             ^
## In destructor 'virtual pointedToBase::~pointedToBase()',
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:144:14,
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:132:8,
##     inlined from 'nimSmartPtr<T>::~nimSmartPtr() [with T = waicNimbleList]' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:116:29,
##     inlined from 'double MCMC::calculateWAIC(int)' at P_1_MCMC.cpp:1724:37:
## C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:147:29: warning: 'void operator delete(void*)' called on pointer '<anonymous>.nimSmartPtr<waicNimbleList>::realPtr' with nonzero offset 56 [-Wfree-nonheap-object]
##   147 |   virtual ~pointedToBase() {};
##       |                             ^
## In destructor 'virtual pointedToBase::~pointedToBase()',
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:144:14,
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:132:8,
##     inlined from 'nimSmartPtr<T>::~nimSmartPtr() [with T = waicNimbleList]' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:116:29,
##     inlined from 'double MCMC::calculateWAIC(int)' at P_1_MCMC.cpp:1726:1:
## C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:147:29: warning: 'void operator delete(void*)' called on pointer '<anonymous>.nimSmartPtr<waicNimbleList>::realPtr' with nonzero offset 56 [-Wfree-nonheap-object]
##   147 |   virtual ~pointedToBase() {};
##       |                             ^
## In destructor 'virtual pointedToBase::~pointedToBase()',
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:144:14,
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:132:8,
##     inlined from 'nimSmartPtr<T>::~nimSmartPtr() [with T = waicNimbleList]' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:116:29,
##     inlined from 'nimSmartPtr<waicNimbleList> MCMC::getWAIC()' at P_1_MCMC.cpp:1731:31:
## C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:147:29: warning: 'void operator delete(void*)' called on pointer '<anonymous>.nimSmartPtr<waicNimbleList>::realPtr' with nonzero offset 56 [-Wfree-nonheap-object]
##   147 |   virtual ~pointedToBase() {};
##       |                             ^
## In destructor 'virtual pointedToBase::~pointedToBase()',
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:144:14,
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:132:8,
##     inlined from 'nimSmartPtr<T>::~nimSmartPtr() [with T = waicNimbleList]' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:116:29,
##     inlined from 'nimSmartPtr<waicNimbleList> MCMC::getWAIC()' at P_1_MCMC.cpp:1735:18:
## C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:147:29: warning: 'void operator delete(void*)' called on pointer '<unknown>' with nonzero offset 56 [-Wfree-nonheap-object]
##   147 |   virtual ~pointedToBase() {};
##       |                             ^
## P_1_MCMC.cpp: In member function 'nimSmartPtr<waicNimbleList> MCMC::getWAIC()':
## P_1_MCMC.cpp:1735:18: note: returned from 'void* operator new(std::size_t)'
##  1735 |  Interm_57 = new waicNimbleList;
##       |                  ^~~~~~~~~~~~~~
## In destructor 'virtual pointedToBase::~pointedToBase()',
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:144:14,
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:132:8,
##     inlined from 'nimSmartPtr<T>::~nimSmartPtr() [with T = waicNimbleList]' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:116:29,
##     inlined from 'nimSmartPtr<waicNimbleList> MCMC::getWAIC()' at P_1_MCMC.cpp:1741:1:
## C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:147:29: warning: 'void operator delete(void*)' called on pointer '<unknown>' with nonzero offset 56 [-Wfree-nonheap-object]
##   147 |   virtual ~pointedToBase() {};
##       |                             ^
## P_1_MCMC.cpp: In member function 'nimSmartPtr<waicNimbleList> MCMC::getWAIC()':
## P_1_MCMC.cpp:1735:18: note: returned from 'void* operator new(std::size_t)'
##  1735 |  Interm_57 = new waicNimbleList;
##       |                  ^~~~~~~~~~~~~~
## In destructor 'virtual pointedToBase::~pointedToBase()',
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:144:14,
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:132:8,
##     inlined from 'nimSmartPtr<T>::~nimSmartPtr() [with T = waicNimbleList]' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:116:29,
##     inlined from 'nimSmartPtr<waicNimbleList> MCMC::getWAIC()' at P_1_MCMC.cpp:1741:1:
## C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:147:29: warning: 'void operator delete(void*)' called on pointer '<anonymous>.nimSmartPtr<waicNimbleList>::realPtr' with nonzero offset 56 [-Wfree-nonheap-object]
##   147 |   virtual ~pointedToBase() {};
##       |                             ^
## In destructor 'virtual pointedToBase::~pointedToBase()',
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:144:14,
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:132:8,
##     inlined from 'nimSmartPtr<T>::~nimSmartPtr() [with T = waicDetailsNimbleList]' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:116:29,
##     inlined from 'nimSmartPtr<waicDetailsNimbleList> MCMC::getWAICdetails(bool)' at P_1_MCMC.cpp:1746:38:
## C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:147:29: warning: 'void operator delete(void*)' called on pointer '<anonymous>.nimSmartPtr<waicDetailsNimbleList>::realPtr' with nonzero offset 56 [-Wfree-nonheap-object]
##   147 |   virtual ~pointedToBase() {};
##       |                             ^
## In destructor 'virtual pointedToBase::~pointedToBase()',
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:144:14,
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:132:8,
##     inlined from 'nimSmartPtr<T>::~nimSmartPtr() [with T = waicDetailsNimbleList]' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:116:29,
##     inlined from 'nimSmartPtr<waicDetailsNimbleList> MCMC::getWAICdetails(bool)' at P_1_MCMC.cpp:1750:18:
## C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:147:29: warning: 'void operator delete(void*)' called on pointer '<unknown>' with nonzero offset 56 [-Wfree-nonheap-object]
##   147 |   virtual ~pointedToBase() {};
##       |                             ^
## P_1_MCMC.cpp: In member function 'nimSmartPtr<waicDetailsNimbleList> MCMC::getWAICdetails(bool)':
## P_1_MCMC.cpp:1750:18: note: returned from 'void* operator new(std::size_t)'
##  1750 |  Interm_59 = new waicDetailsNimbleList;
##       |                  ^~~~~~~~~~~~~~~~~~~~~
## In destructor 'virtual pointedToBase::~pointedToBase()',
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:144:14,
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:132:8,
##     inlined from 'nimSmartPtr<T>::~nimSmartPtr() [with T = waicDetailsNimbleList]' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:116:29,
##     inlined from 'nimSmartPtr<waicDetailsNimbleList> MCMC::getWAICdetails(bool)' at P_1_MCMC.cpp:1758:1:
## C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:147:29: warning: 'void operator delete(void*)' called on pointer '<unknown>' with nonzero offset 56 [-Wfree-nonheap-object]
##   147 |   virtual ~pointedToBase() {};
##       |                             ^
## P_1_MCMC.cpp: In member function 'nimSmartPtr<waicDetailsNimbleList> MCMC::getWAICdetails(bool)':
## P_1_MCMC.cpp:1750:18: note: returned from 'void* operator new(std::size_t)'
##  1750 |  Interm_59 = new waicDetailsNimbleList;
##       |                  ^~~~~~~~~~~~~~~~~~~~~
## In destructor 'virtual pointedToBase::~pointedToBase()',
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:144:14,
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:132:8,
##     inlined from 'nimSmartPtr<T>::~nimSmartPtr() [with T = waicDetailsNimbleList]' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:116:29,
##     inlined from 'nimSmartPtr<waicDetailsNimbleList> MCMC::getWAICdetails(bool)' at P_1_MCMC.cpp:1758:1:
## C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:147:29: warning: 'void operator delete(void*)' called on pointer '<anonymous>.nimSmartPtr<waicDetailsNimbleList>::realPtr' with nonzero offset 56 [-Wfree-nonheap-object]
##   147 |   virtual ~pointedToBase() {};
##       |                             ^
## In destructor 'virtual pointedToBase::~pointedToBase()',
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:144:14,
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:132:8,
##     inlined from 'nimSmartPtr<T>::~nimSmartPtr() [with T = waicNimbleList]' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:116:29,
##     inlined from 'SEXPREC* CALL_MCMC_getWAIC(SEXP)' at P_1_MCMC.cpp:1913:78:
## C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:147:29: warning: 'void operator delete(void*)' called on pointer '<anonymous>.nimSmartPtr<waicNimbleList>::realPtr' with nonzero offset 56 [-Wfree-nonheap-object]
##   147 |   virtual ~pointedToBase() {};
##       |                             ^
## In destructor 'virtual pointedToBase::~pointedToBase()',
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:144:14,
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:132:8,
##     inlined from 'nimSmartPtr<T>::~nimSmartPtr() [with T = waicDetailsNimbleList]' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:116:29,
##     inlined from 'SEXPREC* CALL_MCMC_getWAICdetails(SEXP, SEXP)' at P_1_MCMC.cpp:1931:85:
## C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:147:29: warning: 'void operator delete(void*)' called on pointer '<anonymous>.nimSmartPtr<waicDetailsNimbleList>::realPtr' with nonzero offset 56 [-Wfree-nonheap-object]
##   147 |   virtual ~pointedToBase() {};
##       |                             ^
## In destructor 'virtual pointedToBase::~pointedToBase()',
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:144:14,
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:132:8,
##     inlined from 'void nimSmartPtr<T>::setPtr(const nimSmartPtr<T>&) [with T = waicNimbleList]' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:49:39,
##     inlined from 'nimSmartPtr<T>& nimSmartPtr<T>::operator=(const nimSmartPtr<T>&) [with T = waicNimbleList]' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:79:11,
##     inlined from 'virtual nimSmartPtr<waicNimbleList> waicClass::get()' at P_1_MCMC.cpp:1271:14:
## C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:147:29: warning: 'void operator delete(void*)' called on pointer '*<return-value>.nimSmartPtr<waicNimbleList>::realPtr' with nonzero offset 56 [-Wfree-nonheap-object]
##   147 |   virtual ~pointedToBase() {};
##       |                             ^
## In destructor 'virtual pointedToBase::~pointedToBase()',
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:144:14,
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:132:8,
##     inlined from 'nimSmartPtr<T>::~nimSmartPtr() [with T = waicNimbleList]' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:116:29,
##     inlined from 'virtual nimSmartPtr<waicNimbleList> waicClass::get()' at P_1_MCMC.cpp:1271:14:
## C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:147:29: warning: 'void operator delete(void*)' called on pointer '<unknown>' with nonzero offset 56 [-Wfree-nonheap-object]
##   147 |   virtual ~pointedToBase() {};
##       |                             ^
## P_1_MCMC.cpp: In member function 'virtual nimSmartPtr<waicNimbleList> waicClass::get()':
## P_1_MCMC.cpp:1271:14: note: returned from 'void* operator new(std::size_t)'
##  1271 | output = new waicNimbleList;
##       |              ^~~~~~~~~~~~~~
## In destructor 'virtual pointedToBase::~pointedToBase()',
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:144:14,
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:132:8,
##     inlined from 'void nimSmartPtr<T>::setPtr(const nimSmartPtr<T>&) [with T = waicDetailsNimbleList]' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:49:39,
##     inlined from 'nimSmartPtr<T>& nimSmartPtr<T>::operator=(const nimSmartPtr<T>&) [with T = waicDetailsNimbleList]' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:79:11,
##     inlined from 'virtual nimSmartPtr<waicDetailsNimbleList> waicClass::getDetails(bool)' at P_1_MCMC.cpp:1297:14:
## C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:147:29: warning: 'void operator delete(void*)' called on pointer '*<return-value>.nimSmartPtr<waicDetailsNimbleList>::realPtr' with nonzero offset 56 [-Wfree-nonheap-object]
##   147 |   virtual ~pointedToBase() {};
##       |                             ^
## In destructor 'virtual pointedToBase::~pointedToBase()',
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:144:14,
##     inlined from 'void pointedToBase::removeWatcher()' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:132:8,
##     inlined from 'nimSmartPtr<T>::~nimSmartPtr() [with T = waicDetailsNimbleList]' at C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:116:29,
##     inlined from 'virtual nimSmartPtr<waicDetailsNimbleList> waicClass::getDetails(bool)' at P_1_MCMC.cpp:1297:14:
## C:\Software\R\R-4.3.3\library\nimble\include/nimble/smartPtrs.h:147:29: warning: 'void operator delete(void*)' called on pointer '<unknown>' with nonzero offset 56 [-Wfree-nonheap-object]
##   147 |   virtual ~pointedToBase() {};
##       |                             ^
## P_1_MCMC.cpp: In member function 'virtual nimSmartPtr<waicDetailsNimbleList> waicClass::getDetails(bool)':
## P_1_MCMC.cpp:1297:14: note: returned from 'void* operator new(std::size_t)'
##  1297 | output = new waicDetailsNimbleList;
##       |              ^~~~~~~~~~~~~~~~~~~~~
## running chain 1...
## |-------------|-------------|-------------|-------------|
## |-------------------------------------------------------|
## running chain 2...
## |-------------|-------------|-------------|-------------|
## |-------------------------------------------------------|
##   [Warning] There are 20 individual pWAIC values that are greater than 0.4. This may indicate that the WAIC estimate is unstable (Vehtari et al., 2017), at least in cases without grouping of data nodes or multivariate data nodes.
nimbleOptions(showCompilerOutput = FALSE)

# See https://stats.stackexchange.com/q/304958 for discussion about WAIC warning

## View raw list output returned my the MCMC sampler ---------------------------

# Sampled values from the posterior distribution (n = n_iter - n_burin = 5,000)

utils::head(as.data.frame.matrix(bym_samples$samples$chain1), n = 10) 
# Summarised sample values from the posterior distribution (mean, median, std and quantiles 2.5 and 97.5)
utils::head(bym_samples$summary$all.chains, n = 100)
##                            Mean     Median     St.Dev.   95%CI_low 95%CI_upp
## alpha                0.08888225 0.08930684 0.054984245 -0.02050222 0.1950861
## overall.sir          1.09460332 1.09341611 0.060121745  0.97970652 1.2154157
## residual.sir[1]      4.19434953 4.01978947 1.345700071  2.09085853 7.3304194
## residual.sir[2]      3.98422997 3.94304653 0.654064703  2.81293104 5.3804117
## residual.sir[3]      3.21591734 3.12435009 0.926864797  1.68128101 5.2882493
## residual.sir[4]      2.20131752 2.09530699 0.727440636  1.08713965 3.8855379
## residual.sir[5]      3.09086336 3.02883792 0.721573206  1.85486951 4.6868241
## residual.sir[6]      3.05292076 2.92076194 1.081827752  1.32380660 5.5151877
## residual.sir[7]      2.79297151 2.75102063 0.514265726  1.90344820 3.9129221
## residual.sir[8]      2.77959150 2.64308822 1.046786258  1.12588491 5.2024974
## residual.sir[9]      2.15076234 2.05961848 0.658081077  1.12995935 3.6847060
## residual.sir[10]     2.63240992 2.58951711 0.539666035  1.70527042 3.7995918
## residual.sir[11]     2.69481194 2.61806477 0.751047418  1.43471827 4.3582448
## residual.sir[12]     2.77096704 2.64319965 0.963928987  1.26321280 5.0158753
## residual.sir[13]     2.34322035 2.20479030 0.898523370  1.01142511 4.4612676
## residual.sir[14]     1.52416634 1.45119930 0.512304980  0.73588283 2.7167010
## residual.sir[15]     1.80033048 1.76178865 0.432697630  1.06819010 2.7594371
## residual.sir[16]     1.76537128 1.71575566 0.438046810  1.04536880 2.7533227
## residual.sir[17]     1.88321201 1.80073372 0.606796901  0.94866697 3.3128443
## residual.sir[18]     1.18518346 1.14546659 0.335929601  0.64852732 1.9523539
## residual.sir[19]     1.85583331 1.82003498 0.445506568  1.09196387 2.8321698
## residual.sir[20]     1.34513503 1.29242071 0.419249990  0.67763496 2.3088171
## residual.sir[21]     1.28260716 1.25641890 0.299746288  0.77646827 1.9408987
## residual.sir[22]     1.31154786 1.29716693 0.228629297  0.90402982 1.7988778
## residual.sir[23]     1.11280477 1.08553367 0.280295857  0.64678173 1.7345997
## residual.sir[24]     0.76302355 0.73788680 0.203904875  0.43731386 1.2314145
## residual.sir[25]     1.14798957 1.12903926 0.237490983  0.73873557 1.6702256
## residual.sir[26]     1.05891204 1.03586443 0.247566029  0.64165582 1.6093600
## residual.sir[27]     0.93797334 0.90417766 0.279611066  0.49251495 1.5850276
## residual.sir[28]     0.99618800 0.96980534 0.258330736  0.56853785 1.5732725
## residual.sir[29]     1.06857011 1.05301637 0.198565674  0.72443589 1.5012238
## residual.sir[30]     0.74626759 0.72547545 0.188672452  0.44023846 1.1762212
## residual.sir[31]     0.83967779 0.81038068 0.235647813  0.46328729 1.3811640
## residual.sir[32]     1.01496591 0.95714181 0.379752297  0.44818625 1.9124147
## residual.sir[33]     0.82437229 0.79598959 0.239200301  0.44011285 1.3689848
## residual.sir[34]     0.70683634 0.68989463 0.171421856  0.42291093 1.0937958
## residual.sir[35]     0.81201482 0.79082735 0.203357353  0.47172132 1.2606303
## residual.sir[36]     0.75176577 0.72723699 0.224712819  0.38582863 1.2644956
## residual.sir[37]     0.72799869 0.70845597 0.186846988  0.41760312 1.1492603
## residual.sir[38]     0.59830951 0.57774309 0.163896525  0.33726396 0.9804305
## residual.sir[39]     0.76688129 0.73701892 0.239843769  0.38282293 1.3130773
## residual.sir[40]     0.60095109 0.57228065 0.203947985  0.28711665 1.0798193
## residual.sir[41]     0.49746881 0.48621237 0.121687332  0.29293678 0.7689146
## residual.sir[42]     0.52911524 0.51670271 0.134269622  0.30345724 0.8257039
## residual.sir[43]     0.67956629 0.64804483 0.233171717  0.31647341 1.2208839
## residual.sir[44]     0.45326410 0.44085065 0.121084933  0.25350563 0.7255143
## residual.sir[45]     0.40860069 0.40315251 0.079934476  0.26717590 0.5792874
## residual.sir[46]     0.49794373 0.48161625 0.144892793  0.26163563 0.8270021
## residual.sir[47]     0.46101428 0.44275794 0.144409459  0.23308434 0.7917519
## residual.sir[48]     0.40765878 0.39054498 0.132278576  0.19737356 0.7127791
## residual.sir[49]     0.32920000 0.32607601 0.051890556  0.23629258 0.4398097
## residual.sir[50]     0.42971437 0.41710674 0.126353077  0.22114717 0.7136726
## residual.sir[51]     0.48466454 0.45741486 0.183549647  0.20904924 0.9168867
## residual.sir[52]     0.44294682 0.41708205 0.170492503  0.18867031 0.8454339
## residual.sir[53]     0.37186436 0.35312577 0.136078109  0.16213393 0.6852044
## residual.sir[54]     0.38469759 0.36893600 0.128440035  0.18019660 0.6785512
## residual.sir[55]     0.55345997 0.53296943 0.176834449  0.26779562 0.9560861
## residual.sir[56]     0.74947383 0.70815494 0.273826363  0.33876662 1.4008366
## residual.sir.gt1[1]  0.99995000 1.00000000 0.007070926  1.00000000 1.0000000
## residual.sir.gt1[2]  1.00000000 1.00000000 0.000000000  1.00000000 1.0000000
## residual.sir.gt1[3]  0.99951000 1.00000000 0.022130630  1.00000000 1.0000000
## residual.sir.gt1[4]  0.98601000 1.00000000 0.117449640  1.00000000 1.0000000
## residual.sir.gt1[5]  0.99998000 1.00000000 0.004472114  1.00000000 1.0000000
## residual.sir.gt1[6]  0.99510000 1.00000000 0.069828639  1.00000000 1.0000000
## residual.sir.gt1[7]  1.00000000 1.00000000 0.000000000  1.00000000 1.0000000
## residual.sir.gt1[8]  0.98578000 1.00000000 0.118397347  1.00000000 1.0000000
## residual.sir.gt1[9]  0.99032000 1.00000000 0.097910130  1.00000000 1.0000000
## residual.sir.gt1[10] 0.99999000 1.00000000 0.003162278  1.00000000 1.0000000
## residual.sir.gt1[11] 0.99848000 1.00000000 0.038957731  1.00000000 1.0000000
## residual.sir.gt1[12] 0.99354000 1.00000000 0.080114497  1.00000000 1.0000000
## residual.sir.gt1[13] 0.97657000 1.00000000 0.151265541  1.00000000 1.0000000
## residual.sir.gt1[14] 0.86383000 1.00000000 0.342970709  0.00000000 1.0000000
## residual.sir.gt1[15] 0.98676000 1.00000000 0.114301501  1.00000000 1.0000000
## residual.sir.gt1[16] 0.98287000 1.00000000 0.129756431  1.00000000 1.0000000
## residual.sir.gt1[17] 0.96501000 1.00000000 0.183755374  0.00000000 1.0000000
## residual.sir.gt1[18] 0.68291000 1.00000000 0.465345138  0.00000000 1.0000000
## residual.sir.gt1[19] 0.98864000 1.00000000 0.105976708  1.00000000 1.0000000
## residual.sir.gt1[20] 0.79059000 1.00000000 0.406889552  0.00000000 1.0000000
## residual.sir.gt1[21] 0.82857000 1.00000000 0.376886157  0.00000000 1.0000000
## residual.sir.gt1[22] 0.92441000 1.00000000 0.264342298  0.00000000 1.0000000
## residual.sir.gt1[23] 0.62747000 1.00000000 0.483480854  0.00000000 1.0000000
## residual.sir.gt1[24] 0.12165000 0.00000000 0.326882771  0.00000000 1.0000000
## residual.sir.gt1[25] 0.71812000 1.00000000 0.449917426  0.00000000 1.0000000
## residual.sir.gt1[26] 0.55982000 1.00000000 0.496411152  0.00000000 1.0000000
## residual.sir.gt1[27] 0.36594000 0.00000000 0.481695170  0.00000000 1.0000000
## residual.sir.gt1[28] 0.45324000 0.00000000 0.497811190  0.00000000 1.0000000
## residual.sir.gt1[29] 0.60805000 1.00000000 0.488188059  0.00000000 1.0000000
## residual.sir.gt1[30] 0.09557000 0.00000000 0.294002108  0.00000000 1.0000000
## residual.sir.gt1[31] 0.22206000 0.00000000 0.415633353  0.00000000 1.0000000
## residual.sir.gt1[32] 0.45396000 0.00000000 0.497878296  0.00000000 1.0000000
## residual.sir.gt1[33] 0.21048000 0.00000000 0.407651605  0.00000000 1.0000000
## residual.sir.gt1[34] 0.05750000 0.00000000 0.232796675  0.00000000 1.0000000
## residual.sir.gt1[35] 0.17176000 0.00000000 0.377173601  0.00000000 1.0000000
## residual.sir.gt1[36] 0.13281000 0.00000000 0.339370971  0.00000000 1.0000000
## residual.sir.gt1[37] 0.08322000 0.00000000 0.276215848  0.00000000 1.0000000
## residual.sir.gt1[38] 0.02094000 0.00000000 0.143184222  0.00000000 0.0000000
## residual.sir.gt1[39] 0.15846000 0.00000000 0.365173605  0.00000000 1.0000000
## residual.sir.gt1[40] 0.04188000 0.00000000 0.200315918  0.00000000 1.0000000
## residual.sir.gt1[41] 0.00070000 0.00000000 0.026448384  0.00000000 0.0000000
## residual.sir.gt1[42] 0.00259000 0.00000000 0.050826349  0.00000000 0.0000000
### Check model convergence using the Gelman-Rubin convergence diagnostic ------

# The Gelman-Rubin compares the within chain variation to the between chain
# variation for each parameter. If the chains have converged on the stationary
# distribution, then it should be impossible to distinguish between the chains.
# It is a ratio measures, and values < 1.1 are considered evidence of chain
# convergence.

# gr.diag <- coda::gelman.diag(bym_samples$samples, multivariate = FALSE)
# 
# # List all parameters that are not posterior probabilities
# 
# gr.diag.inc <- stringr::str_subset(base::dimnames(gr.diag$psrf)[[1]], "gt1|lt1", negate = TRUE)
# 
# ## Are all values < 1.1? If yes, this is evidence of convergence ---------------
# 
# base::all(gr.diag$psrf[gr.diag.inc,"Point est."] < 1.1) # Don't check posterior probabilities - these are threshold nodes and do not need to converge
# 
# ## If no, then Which parameters have a value >= 1.1? ---------------------------
# 
# base::which(gr.diag$psrf[gr.diag.inc,"Point est."] > 1.1)

### Check trace, density and autocorrelation plots for convergence -------------

# Import MCMC samples into a ggs that can be used with ggs_* graphical functions

bym_ggmcmc <- ggmcmc::ggs(bym_samples$samples)

## Check the overall SIR -------------------------------------------------------

# Generate trace, density and autocorrelation plots

trace_overall.sir <- bym_ggmcmc %>% 
  dplyr::filter(Parameter == "overall.sir") %>% 
  ggmcmc::ggs_traceplot() +
  ggplot2::theme_bw() +
  ggplot2::theme(text = ggplot2::element_text(size = 12))

density_overall.sir <- bym_ggmcmc %>% 
  dplyr::filter(Parameter == "overall.sir") %>% 
  ggmcmc::ggs_density() +
  ggplot2::theme_bw() +
  ggplot2::theme(text = ggplot2::element_text(size = 12))

acf_overall.sir <- bym_ggmcmc %>%
  dplyr::filter(Parameter == "overall.sir") %>% 
  ggmcmc::ggs_autocorrelation() +
  ggplot2::theme_bw() +
  ggplot2::theme(text = element_text(size = 12))

# Plot visual convergence diagnostics

base::print((trace_overall.sir | density_overall.sir) / acf_overall.sir) +
  patchwork::plot_annotation(title = "Trace, density and autocorrelation plots for overall SIR",
                             theme = ggplot2::theme(plot.title = ggplot2::element_text(hjust = 0.5)))

## Check the spatially variance component --------------------------------------

# Generate trace, density and autocorrelation plots

trace_sigma2.s <- bym_ggmcmc %>% 
  dplyr::filter(Parameter == "sigma2.s") %>% 
  ggmcmc::ggs_traceplot() +
  ggplot2::theme_bw() +
  ggplot2::theme(text = ggplot2::element_text(size = 12))

density_sigma2.s <- bym_ggmcmc %>% 
  dplyr::filter(Parameter == "sigma2.s") %>% 
  ggmcmc::ggs_density() +
  ggplot2::theme_bw() +
  ggplot2::theme(text = ggplot2::element_text(size = 12))

acf_sigma2.s <- bym_ggmcmc %>%
  filter(Parameter == "sigma2.s") %>% 
  ggmcmc::ggs_autocorrelation() +
  ggplot2::theme_bw() +
  ggplot2::theme(text = ggplot2::element_text(size = 12))

# Plot visual convergence diagnostics

base::print((trace_sigma2.s | density_sigma2.s)/acf_sigma2.s) +
  patchwork::plot_annotation(title = "Trace, density and autocorrelation plots for spatially correlated variance component (s)",
                             theme = ggplot2::theme(plot.title = ggplot2::element_text(hjust = 0.5)))

## Check the uncorrelated variance component -----------------------------------

# Generate trace, density and autocorrelation plots

trace_sigma2.u <- bym_ggmcmc %>% 
  dplyr::filter(Parameter == "sigma2.u") %>% 
  ggmcmc::ggs_traceplot() +
  ggplot2::theme_bw() +
  ggplot2::theme(text = ggplot2::element_text(size = 12))

density_sigma2.u <- bym_ggmcmc %>% 
  dplyr::filter(Parameter == "sigma2.u") %>% 
  ggmcmc::ggs_density() +
  ggplot2::theme_bw() +
  ggplot2::theme(text = ggplot2::element_text(size = 12))

acf_sigma2.u <- bym_ggmcmc %>%
  filter(Parameter == "sigma2.u") %>% 
  ggmcmc::ggs_autocorrelation() +
  ggplot2::theme_bw() +
  ggplot2::theme(text = ggplot2::element_text(size = 12))

base::print((trace_sigma2.u | density_sigma2.u) /acf_sigma2.u) +
  patchwork::plot_annotation(title = "Trace, density and autocorrelation plots for uncorrelated variance component (u)",
                             theme = ggplot2::theme(plot.title = ggplot2::element_text(hjust = 0.5)))

## Check the smoothed SIR for Perth-Kinross (29) -------------------------------

# This district has the most neighbours

# Generate trace, density and autocorrelation plots

trace_smoothed.sir_29 <- bym_ggmcmc %>% 
  dplyr::filter(Parameter == "smoothed.sir[29]") %>% 
  ggmcmc::ggs_traceplot() +
  ggplot2::theme_bw() +
  ggplot2::theme(text = ggplot2::element_text(size = 12))

density_smoothed.sir_29 <- bym_ggmcmc %>% 
  dplyr::filter(Parameter == "smoothed.sir[29]") %>% 
  ggmcmc::ggs_density() +
  ggplot2::theme_bw() +
  ggplot2::theme(text = ggplot2::element_text(size = 12))

acf_smoothed.sir_29 <- bym_ggmcmc %>%
  filter(Parameter == "smoothed.sir[29]") %>% 
  ggmcmc::ggs_autocorrelation() +
  ggplot2::theme_bw() +
  ggplot2::theme(text = ggplot2::element_text(size = 12))

# Plot visual convergence diagnostics

base::print((trace_smoothed.sir_29 | density_smoothed.sir_29) / acf_smoothed.sir_29) +
  patchwork::plot_annotation(title = "Trace, density and autocorrelation plots for Perth-Kinross smoothed SIR",
                             theme = ggplot2::theme(plot.title = ggplot2::element_text(hjust = 0.5)))

### Summarise across MCMC samples to obtained BYM model estimates --------------

## Extract alpha, sigma2.s and sigma2.u ----------------------------------------

bym_ests <- bym_samples$summary$all.chains[c("alpha",
                                             "sigma2.s",
                                             "sigma2.u"),
                                           c("Median",
                                             "95%CI_low",
                                             "95%CI_upp")] %>%
  
  # Convert matrix to data frame
  
  base::as.data.frame() %>%
  
  # Rename columns
  
  stats::setNames(c("median", "lower_95_ci", "upper_95_ci")) %>%
  
  # Make the data frame row names an explicit variable called *parameter*
  
  tibble::rownames_to_column(var = "parameter") %>%
  
  # Exponentiate the parameter and 95% CI estimates for alpha to obtain overall SIR effect measure
  
  dplyr::mutate(dplyr::across(c(median, lower_95_ci, upper_95_ci), ~ base::ifelse(parameter == "alpha", base::exp(.), NA), .names = "{.col}_exp")) %>%
  
  # Format estimates as text variables with three decimal places
  
  dplyr::mutate(dplyr::across(dplyr::where(is.numeric), ~ base::ifelse(base::is.na(.), "", base::format(base::round(., 3), nsmall = 3))))

### Print model estimates and WIAC ---------------------------------------------

base::print(list("Model estimate" = bym_ests,
                 "WAIC" = bym_samples$WAIC$WAIC))
## $`Model estimate`
##   parameter median lower_95_ci upper_95_ci median_exp lower_95_ci_exp upper_95_ci_exp
## 1     alpha  0.089      -0.021       0.195      1.093           0.980           1.215
## 2  sigma2.s  0.605       0.316       1.132                                           
## 3  sigma2.u  0.011       0.003       0.066                                           
## 
## $WAIC
## [1] 293.8658
### Summarise across MCMC samples to obtain smoothed SIR estimates -------------

# Create data set of smoothed and residual risk of lip cancer

bym_sf <- lip_sf %>%
  
  # Smoothed SIR estimate
  
  dplyr::bind_cols(bym_samples$summary$all.chains[base::paste0("smoothed.sir[", 1:N, "]"), c("Median", "95%CI_low", "95%CI_upp")] %>%
                     base::as.data.frame() %>%
                     stats::setNames(c("bym_smoothed_sir_est", "bym_smoothed_sir_l95", "bym_smoothed_sir_uci"))) %>%
  
  # Residual SIR estimate
  
  dplyr::bind_cols(bym_samples$summary$all.chains[base::paste0("residual.sir[", 1:N, "]"), c("Median", "95%CI_low", "95%CI_upp")] %>%
                     base::as.data.frame() %>%
                     stats::setNames(c("bym_residual_sir_est", "bym_residual_sir_l95", "bym_residual_sir_uci"))) %>%
  
  # Residual s SIR estimate
  
  dplyr::bind_cols(bym_samples$summary$all.chains[base::paste0("residual.sir.s[", 1:N, "]"), c("Median", "95%CI_low", "95%CI_upp")] %>%
                     base::as.data.frame() %>%
                     stats::setNames(c("bym_residual_sir_s_est", "bym_residual_sir_s_l95", "bym_residual_sir_s_uci"))) %>%
  
  # Residual u SIR estimate
  
  dplyr::bind_cols(bym_samples$summary$all.chains[base::paste0("residual.sir.u[", 1:N, "]"), c("Median", "95%CI_low", "95%CI_upp")] %>%
                     base::as.data.frame() %>%
                     stats::setNames(c("bym_residual_sir_u_est", "bym_residual_sir_u_l95", "bym_residual_sir_u_uci"))) %>%
  
  # Posterior probabilities for residual risk > 1
  
  dplyr::bind_cols(bym_samples$summary$all.chains[base::paste0("residual.sir.gt1[", 1:N, "]"), "Mean"] %>%
                     base::as.data.frame() %>%
                     stats::setNames("bym_residual_sir_gt1")) %>%
  
  # Posterior probabilities for residual risk < 1
  
  dplyr::bind_cols(bym_samples$summary$all.chains[base::paste0("residual.sir.lt1[", 1:N, "]"), "Mean"] %>%
                     base::as.data.frame() %>%
                     stats::setNames("bym_residual_sir_lt1")) %>%
  
  # Annotate exceedence probabilities
  
  dplyr::mutate(bym_residual_sir_cat = dplyr::case_when(bym_residual_sir_gt1 > 0.995 ~ "++",
                                                        bym_residual_sir_gt1 > 0.975 ~ "+",
                                                        bym_residual_sir_lt1 > 0.995 ~ "--",
                                                        bym_residual_sir_lt1 > 0.975 ~ "-",
                                                        .default = ""))

### Map BYM smoothed SIR for districts -----------------------------------------

map_bym_residual_sir <- ggplot() +
  
  # Add SIR estimates
  
  geom_sf(data = bym_sf,
          aes(fill = bym_residual_sir_est),
          col = "grey50",
          linewidth = 0.1) +
  
  # Add SIR posterior probabilities
  
  ggplot2::geom_point(data = bym_sf %>% dplyr::filter(bym_residual_sir_cat != ""),
                      mapping = ggplot2::aes(shape = bym_residual_sir_cat,
                                             geometry = geom),
                      fill = "black",
                      stat = "sf_coordinates") +
  
  # Add Scotland boundary
  
  ggplot2::geom_sf(data = sct_sf,
                   fill = NA,
                   colour = "Black",
                   linewidth = 1) +
  
  # Add fill aesthetic gradient mapping
  
  ggplot2::scale_fill_gradient2("Smoothed SIR",
                                low = col_pal["low"], # blue
                                mid = col_pal["mid"], # yellow
                                high = col_pal["high"], # darkblue
                                midpoint = 0,
                                na.value = NA,
                                limits = c(base::exp(-max_log_sir), base::exp(max_log_sir)),
                                breaks = base::exp(base::seq(-max_log_sir, max_log_sir, 0.5)),
                                labels = base::format(base::round(exp(seq(-max_log_sir, max_log_sir, 0.5)), 2), nsmall = 2),
                                trans = "log") +
  
  # Add shape aesthic mapping
  
  ggplot2::scale_shape_manual("Posterior probabilities",
                              values = c("++" = 24,
                                         "+" = 2,
                                         "-" = 6,
                                         "--" = 25),
                              breaks = c("++", "+", "-", "--"),
                              labels = c("++" = "SIR > 1, p > 97.5%",
                                         "+" = "SIR > 1, p > 95.0%",
                                         "-" = "SIR < 1, p > 95.0%",
                                         "--" = "SIR < 1, p > 97.5%")) +
  
  # Format legends
  
  guides(fill = guide_colourbar(frame.colour = "black", 
                                frame.linewidth = 0.25,
                                ticks.colour = "black",
                                ticks.linewidth = 0.25,
                                order = 1),
         shape = guide_legend(order = 2)) +
  
  # Format map
  
  theme_bw() + 
  
  theme(axis.title = ggplot2::element_blank(),
        axis.text = ggplot2::element_blank(),
        axis.ticks = ggplot2::element_blank(),
        
        legend.position = "inside",
        legend.margin = ggplot2::margin(0, 0, 0, 0),
        legend.position.inside = c(0.15, 0.88),
        
        panel.grid = ggplot2::element_blank(),
        
        text = ggplot2::element_text(size = 12))

## Output observed and BYM smoothed SIR for lip cancer risk --------------------

(map_obs_sir | map_bym_residual_sir) +
  patchwork::plot_annotation(title = "Observed and BYM smoothed SIR for male lip cancer in Scotland (1975-1980)", 
                             theme = theme(plot.title = element_text(hjust = 0.5)))

References

Clayton D, Kaldor J. Empirical Bayes estimates of age standardised relative risks for use in disease mapping. Biometrics 1987;43:671–681. doi: 10.2307/2532003

Cressie NAC. Statistics for spatial data. New York: John Wiley & Sons; 1993. p. 537 (Table 7.2). doi: 10.1002/9781119115151

Stern H, Cressie N. Inferences for extremes in disease mapping. In Lawson AB, Biggeri A, Böhning D, et al., editors. Disease mapping and risk assessment for public health. New York: Wiley; 1999. pp. 68–69 (Table 5.1). Available at Storage General (614.42 41)

LS0tDQp0aXRsZTogUFVCSDUxMjUgRW52aXJvbm1lbnRhbCBhbmQgU29jaWFsIEVwaWRlbWlvbG9neQ0KICA8YnI+DQogIDxwIHN0eWxlPSJjb2xvcjojOTkwMDAwOyBmb250LXNpemU6NDRwdDsgZm9udC13ZWlnaHQ6Ym9sZGVyOyI+RW52aXJvbm1lbnRhbCBFcGlkZW1pb2xvZ3kgU3R1ZHkgRGVzaWduczo8YnI+RGlzZWFzZSBNYXBwaW5nIERlbW9uc3RyYXRpb248L3A+PC9icj4NCiAgIyA8cCBzdHlsZT0iZm9udC1zaXplOjM4cHQiPiZuYnNwOzwvcD4NCmF1dGhvcjogPHAgc3R5bGU9ImZvbnQtc2l6ZToxOHB0OyBmb250LXdlaWdodDpub3JtYWwiPjMwIEFwcmlsIDIwMjU8L3A+DQogIDxwPkRyIERhcnJlbiBNYXluZTwvcD4NCiAgPHAgc3R5bGU9ImZvbnQtc2l6ZToxOHB0OyBmb250LXdlaWdodDpub3JtYWw7Ij5QdWJsaWMgSGVhbHRoIEVwaWRlbWlvbG9naXN0PGJyPklsbGF3YXJyYSBTaG9hbGhhdmVuIExvY2FsIEhlYWx0aCBEaXN0cmljdDxicj4NCiAgPGJyPg0KICBBZGp1bmN0IFNlbmlvciBMZWN0dXJlcjxicj5GYWN1bHR5IG9mIE1lZGljaW5lLCBTY2hvb2wgb2YgUHVibGljIEhlYWx0aDwvcD48L3NwYW4+DQpkYXRlOiBGdWxsIFJTdHVkaW8gcHJvamVjdCBjb2RlIGF2YWlsYWJsZSBmcm9tIDxhIGhyZWY9Imh0dHBzOi8vZ2l0aHViLmNvbS9kbWF5ODUxOS9QVUJINTEyNV9EWE1BUF9ERU1PIiB0YXJnZXQ9Il9ibGFuayIgcmVsPSJub29wZW5lciBub3JlZmVycmVyIj5odHRwczovL2dpdGh1Yi5jb20vZG1heTg1MTkvUFVCSDUxMjVfRFhNQVBfREVNTzwvYT4uPGJyPg0KICBTdGFuZGFsb25lIFIgbWFya2Rvd24gKFJtZCkgY29kZSBjYW4gYmUgZG93bmxvZGVkIHVzaW5nIHRoZSA8Yj5Db2RlPC9iPiBidXR0b24gaW4gdGhlIHRvcCByaWdodCBoYW5kIGNvcm5lciBhbmQgc2VsZWN0aW5nIDxiPkRvd25sb2FkIFJtZDwvYj4uDQogIDxwPjxhIGhyZWY9Imh0dHBzOi8vZ2l0aHViLmNvbS9kbWF5ODUxOS9QVUJINTEyNV9EWE1BUF8yMDI1IiB0YXJnZXQ9Il9ibGFuayIgcmVsPSJub29wZW5lciBub3JlZmVycmVyIj5FbnZpcm9ubWVudGFsIEVwaWRlbWlvbG9neSBTdHVkeSBEZXNpZ25zIC0tLSBEaXNlYXNlIE1hcHBpbmcgRGVtb25zdHJhdGlvbjwvYT4gKFBVQkg1MTI1X0RYTUFQX0RFTU8pIGJ5IDxhIGhyZWY9Imh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9pbi90aGVtYXluZXN0b3J5IiANCiAgdGFyZ2V0PSJfYmxhbmsiIHJlbD0ibm9vcGVuZXIgbm9yZWZlcnJlciI+RGFycmVuIE1heW5lPC9hPiBpcyBsaWNlbnNlZCB1bmRlciA8YSBocmVmPSJodHRwczovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvYnktbmMtc2EvNC4wLz9yZWY9Y2hvb3Nlci12MSIgdGFyZ2V0PSJfYmxhbmsiIHJlbD0ibm9vcGVuZXIgbm9yZWZlcnJlciI+Q3JlYXRpdmUgQ29tbW9ucyBBdHRyaWJ1dGlvbi1Ob25Db21tZXJjaWFsLVNoYXJlQWxpa2UgNC4wIA0KICBJbnRlcm5hdGlvbmFsPC9hPiA8aW1nIHNyYz0iaHR0cHM6Ly9taXJyb3JzLmNyZWF0aXZlY29tbW9ucy5vcmcvcHJlc3NraXQvYnV0dG9ucy84OHgzMS9wbmcvYnktbmMtc2EucG5nIiBhbHQ9IkJZIE5DIFNBIiBoZWlnaHQ9IjIwcHgiIGhzcGFjZT0iMXB4Ij48L3A+PGJyPg0Kb3V0cHV0Og0KICAgIGh0bWxfZG9jdW1lbnQ6DQogICAgICAjIGNzczogYXNzZXRzL3Jhbnlfc3R5bGUuY3NzDQogICAgICBkZl9wcmludDogcGFnZWQNCiAgICAgIHRoZW1lOiByZWFkYWJsZQ0KICAgICAgaGlnaGxpZ2h0OiB0YW5nbw0KICAgICAgdG9jOiB5ZXMNCiAgICAgIHRvY19mbG9hdDoNCiAgICAgICAgY29sbGFwc2VkOiBUUlVFDQogICAgICBudW1iZXJfc2VjdGlvbnM6IEZBTFNFDQogICAgICBjb2RlX2ZvbGRpbmc6IHNob3cNCiAgICAgIGNvZGVfZG93bmxvYWQ6IFRSVUUNCi0tLQ0KDQo8IS0tIEFkZCBpbmxpbmUgc3R5bGUgc2hlZXQgLS0+DQoNCjwhLS0gYGBge2NzcywgZWNobyA9IEZBTFNFfSAtLT4NCg0KYGBgez1odG1sfQ0KPHN0eWxlID0gdGV4dC9jc3M+DQoNCi5tYWluLWNvbnRhaW5lciB7DQogIG1heC13aWR0aDogMTAwJSAhaW1wb3J0YW50Ow0KICBtYXJnaW46IGF1dG87DQp9DQoNCmJvZHkgew0KICBmb250LWZhbWlseTogIlB1YmxpYyBTYW5zIExpZ2h0IjsNCiAgZm9udC1zaXplOiAxOHB0Ow0KfQ0KDQpoMSB7DQogICAgZm9udC1mYW1pbHk6ICJQdWJsaWMgU2FucyBMaWdodCI7DQogICAgZm9udC1zaXplOiAxOHB0Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGNvbG9yOiAjNDY3ZDYyOw0KfQ0KDQpoMS50aXRsZSB7DQogICAgZm9udC1mYW1pbHk6ICJQdWJsaWMgU2FucyBMaWdodCI7DQogICAgZm9udC1zaXplOiAzOHB0Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIHRleHQtYWxpZ246Y2VudGVyOw0KICAgIGNvbG9yOiBibGFjazsNCn0NCg0KaDIgew0KICAgIGZvbnQtZmFtaWx5OiAiUHVibGljIFNhbnMgTGlnaHQiOw0KICAgIGZvbnQtc2l6ZTogMjhwdDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBjb2xvcjogIzk5MDAwMDsNCn0NCg0KLyoNCg0KaDMgew0KICAgIGZvbnQtZmFtaWx5OiAiUHVibGljIFNhbnMgTGlnaHQiOw0KICAgIGZvbnQtc2l6ZTogMzhwdDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBjb2xvcjogYmxhY2s7DQp9DQoNCiovDQoNCmgzIHsNCiAgICBmb250LWZhbWlseTogIlB1YmxpYyBTYW5zIExpZ2h0IjsNCiAgICBmb250LXNpemU6IDIycHQ7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgY29sb3I6ICNGQjUxNTE7DQp9DQoNCi5hdXRob3Igew0KICAgIGZvbnQtZmFtaWx5OiAiUHVibGljIFNhbnMgTGlnaHQiOw0KICAgIGZvbnQtc2l6ZTogMjhwdDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICB0ZXh0LWFsaWduOiBjZW50ZXI7DQogICAgY29sb3I6IGJsYWNrOw0KfQ0KDQouZGF0ZSB7DQogICAgZm9udC1mYW1pbHk6ICJQdWJsaWMgU2FucyBMaWdodCI7DQogICAgZm9udC1zaXplOiAxNHB0Ow0KICAgIGZvbnQtd2VpZ2h0OiBub3JtYWw7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCiAgICBjb2xvcjogYmxhY2s7DQp9DQoNCi5jb2RlLWZvbGRpbmctYnRuIHsNCiAgZm9udC1mYW1pbHk6ICJQdWJsaWMgU2FucyBMaWdodCI7DQogIGZvbnQtc2l6ZTogMTBwdDsNCiAgPCEtLSBkaXNwbGF5OiBub25lOyAtLT4NCn0NCg0KLyogU2V0IGdsb2JhbCBtYXhpbXVtIGhlaWdodCBmb3IgYWxsIGNodW5rcyAqLw0KDQpwcmUgew0KICBiYWNrZ3JvdW5kLWNvbG9yOiB3aGl0ZTsNCiAgbWF4LWhlaWdodDogMTAwJTsNCiAgb3ZlcmZsb3cteTogYXV0bzsNCn0NCg0KLyogTGltaXQgaGVpZ2h0IG9mIDxQUkU+IGJsb2NrcyB0byAxMDBweCAqLw0KDQpwcmVbY2xhc3NdIHsNCiAgYmFja2dyb3VuZC1jb2xvcjogd2hpdGU7DQogIG1heC1oZWlnaHQ6IDEwMCU7DQp9DQoNCi8qIExpbWl0cyBjaHVuayBjb2RlcyB0byAxMDBweCAqLw0KDQouc2Nyb2xsLTEwMCB7DQogIG1heC1oZWlnaHQ6IDEwMHB4Ow0KICBvdmVyZmxvdy15OiBhdXRvOw0KfQ0KDQovKiBTdHlsZSBjbGFzcyBzZWxlY3RvciBmb3IgPHByZT48L3ByZT4gdGFncyAtIHNvdXJjZS9vdXRwdXQgY29udGFpbmVycyAqLyANCg0KLnRleHRQcmUgew0KICBmb250LWZhbWlseTogbW9ubzsNCiAgZm9udC1zaXplOiAxMHB0Ow0KICBiYWNrZ3JvdW5kLWNvbG9yOiB3aGl0ZTsNCn0NCg0KLyogSGFjayByZXF1aXJlZCB0byBnZXQgUGFuZG9jIHRvIHJlbmRlciBsaW5lIG51bWJlcnMgKi8gDQoNCi5zb3VyY2VDb2RlIHsNCiAgb3ZlcmZsb3c6IHZpc2libGU7DQp9DQoNCi8qIEFkanVzdCBUT0Mgd2lkdGggYW5kIGZvbnQgc2l6ZSAqLw0KDQpkaXYudG9jaWZ5IHsNCiAgZm9udC1zaXplOiAxMnB0Ow0KICBtYXgtd2lkdGg6IDEwMCU7DQp9DQoNCi8qIEltcGxlbWVudCBoYW5naW5nIHBhcmFncmFwaCBpbmRlbnRhdGlvbiBpbiByZWZlcmVuY2UgbGlzdCovDQoNCi5ubG0tcmVmZXJlbmNlIHsNCiAgcGFkZGluZy1sZWZ0OiAzMHB4Ow0KICB0ZXh0LWluZGVudDogLTMwcHg7DQp9DQoNCjwvc3R5bGU+DQpgYGANCg0KPCEtLSBgYGAgLS0+DQoNCiMjIEJhY2tncm91bmQNCg0KPGRpdiBzdHlsZT0ibGluZS1oZWlnaHQ6Mi4wOyI+DQoqIFRoaXMgc2Vzc2lvbiB3aWxsIGRlbW9uc3RyYXRlIGZpdHRpbmcgdGhlIEJlc2FnLCBZb3JrLCBhbmQgTW9sbGnDqSAoMTk5MSkgY29uZGl0aW9uYWwgYXV0b3JlZ3Jlc3NpdmUgKENBUikgbW9kZWwgZm9yIGRpc2Vhc2UgbWFwcGluZyBhbmQgZWNvbG9naWNhbCByZWdyZXNzaW9uIGFwcGxpY2F0aW9ucyBpbnZvbHZpbmcgYXJlYWwgZGF0YS4NCg0KKiBXZSB3aWxsIHVzZSBhIGNsYXNzaWMgZGF0YSBzZXQgZmlyc3QgcmVwb3J0ZWQgYnkgQ2xheXRvbiBhbmQgS2FsZG9yICgxOTg3KSB0aGF0IGRlc2NyaWJlcyB0aGUgaW5jaWRlbmNlIG9mIG1hbGUgbGlwIGNhbmNlciB3aXRoaW4gU2NvdHRpc2ggYWRtaW5pc3RyYXRpb24gZGlzdHJpY3RzIGZyb20gMTk3NSB0byAxOTgwLg0KDQoqIFRoZSBkYXRhIHNldCB3YXMgc3Vic2VxdWVudGx5IGV4cGFuZGVkIHRvIGluY2x1ZGUgdGhlIG51bWJlciBvZiBtYWxlIHBvcHVsYXRpb24teWVhcnMgYXQtcmlzayAoQ3Jlc3NpZSwgMTk5MykgYW5kIHRoZSBleHBlY3RlZCBudW1iZXIgb2YgbGlwIGNhbmNlciBjYXNlcyBhbmQgcGVyY2VudGFnZSBvZiBtYWxlcyBlbXBsb3llZCBpbiBhZ3JpY3VsdHVyZSwgZmlzaGluZyBhbmQgZm9yZXN0cnkgKEFGRikgKFN0ZXJuICYgQ3Jlc3NpZSwgMTk5OSkgaW4gZWFjaCBkaXN0cmljdC4NCg0KKiBUaGUgbWFwIG9mIFNjb3R0aXNoIGFkbWluaXN0cmF0aXZlIGRpc3RyaWN0cyBpcyBhIHBvc3QtcHJvY2Vzc2VkIHZlcnNpb24gb2YgdGhlIFNjb3RsYW5kLm1hcCBTLVBsdXMgYm91bmRhcnkgZmlsZSB0aGF0IHdhcyBpbmNsdWRlZCBpbiBXaW5CVUdTIDEuNC4zLCBhIHN0YXRlLW9mLXRoZS1hcnQgMzItYml0IHByb2dyYW0gZm9yIEJheWVzaWFuIGluZmVyZW5jZSB3aGVuIHJlbGVhc2VkIG9uIDZedGheIEF1Z3VzdCAyMDA3IC0tLSBub3csIG5vdCBzbyBtdWNoLi4uDQoNCiogQWxsIGRhdGEgYXJlIGF2YWlsYWJsZSBpbiBhIHNpbmdsZSBaSVAgYXJjaGl2ZSBhdmFpbGFibGUgb24gdGhlIFtHZW9EYSBDZW50cmUgR3VpdEh1YiByZXBvc2l0b3J5XShodHRwczovL2dlb2RhY2VudGVyLmdpdGh1Yi5pby9kYXRhLWFuZC1sYWIvc2NvdGxpcC8pIGFuZCBhcmUgZGVzY3JpYmVkIGluIFRhYmxlIDEgKGNvbHVtbnMgMSBuZCAyKSwgYWxvbmcgd2l0aCB0aGUgc3Vic2V0IG9mIHZhcmlhYmxlcyB1c2VkIGZvciB0aGlzIGRlbW9uc3RyYXRpb24gKGNvbHVtbnMgMyBhbmQgNCkNCjwvZGl2Pg0KDQpUYWJsZSAxOiBEYXRhIHN1bW1hcnkgZm9yIFNjb3R0aXNoIGxpcCBjYW5jZXIgZGF0YSBzZXQgYXZhaWxhYmxlIGZyb20gR2VvRGEgQ2VudHJlIEdpdEh1YiByZXBvc2l0b3J5DQoNCjx0YWJsZSBjbGFzcz0iIGxpZ2h0YWJsZS1jbGFzc2ljIiBzdHlsZT0id2lkdGg9MTQ0MHB4ICFpbXBvcnRhbnQ7IHRhYmxlLWxheW91dDpmaXhlZDsgZm9udC1zaXplOiAxNHB0OyBmb250LWZhbWlseTogUHVibGljIFNhbnMgTGlnaHQ7IG1hcmdpbi1sZWZ0OiBhdXRvOyBtYXJnaW4tcmlnaHQ6IGF1dG87Ij4NCiA8dGhlYWQgc3R5bGU9ImJvcmRlci10b3A6MXB4IHNvbGlkIGJsYWNrOyBib3JkZXItYm90dG9tOjFweCBzb2xpZCBibGFjazsgcGFkZGluZzozcHg7Ij4NCiAgPHRyPg0KICAgPHRoIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQ7IHdpZHRoOiAyMTZweDsiPiBHZW9EYSB2YXJpYWJsZSA8L3RoPg0KICAgPHRoIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQ7IHdpZHRoOiA1MDRweDsiPiBHZW9EYSBkZXNjcmlwdGlvbiA8L3RoPg0KICAgPHRoIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQ7IHdpZHRoOiAyMTZweDsiPiBQVUJINTEyNSB2YXJpYWJsZSA8L3RoPg0KICAgPHRoIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQ7IHdpZHRoOiA1MDRweDsiPiBQVUJINTEyNSBkZXNjcmlwdGlvbiA8L3RoPg0KICA8L3RyPg0KIDwvdGhlYWQ+DQo8dGJvZHk+DQogIDx0cj4NCiAgIDx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0O3dpZHRoOiAxNSU7ICI+IENPREVOTyA8L3RkPg0KICAgPHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQ7d2lkdGg6IDM1JTsgIj4gQ29kZSBjb252ZXJ0ZWQgdG8gbnVtZXJpYyAoZHJvcCB3IHByZWZpeCkgPC90ZD4NCiAgIDx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0O3dpZHRoOiAxNSU7IHRleHQtZGVjb3JhdGlvbjogbGluZS10aHJvdWdoOyAiPiBDT0RFTk8gPC90ZD4NCiAgIDx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0O3dpZHRoOiAzNSU7IHRleHQtZGVjb3JhdGlvbjogbGluZS10aHJvdWdoOyAiPiBDb2RlIGNvbnZlcnRlZCB0byBudW1lcmljIChkcm9wIHcgcHJlZml4KSA8L3RkPg0KICA8L3RyPg0KICA8dHI+DQogICA8dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdDt3aWR0aDogMTUlOyAiPiBBUkVBIDwvdGQ+DQogICA8dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdDt3aWR0aDogMzUlOyAiPiBEaXN0cmljdCBwb2x5Z29uIGFyZWEgPC90ZD4NCiAgIDx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0O3dpZHRoOiAxNSU7IHRleHQtZGVjb3JhdGlvbjogbGluZS10aHJvdWdoOyI+IEFSRUEgPC90ZD4NCiAgIDx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0O3dpZHRoOiAzNSU7IHRleHQtZGVjb3JhdGlvbjogbGluZS10aHJvdWdoOyI+IERpc3RyaWN0IHBvbHlnb24gYXJlYSA8L3RkPg0KICA8L3RyPg0KICA8dHI+DQogICA8dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdDt3aWR0aDogMTUlOyAiPiBQRVJJTUVURVIgPC90ZD4NCiAgIDx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0O3dpZHRoOiAzNSU7ICI+IERpc3RyaWN0IHBvbHlnb24gcGVyaW1ldGVyIDwvdGQ+DQogICA8dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdDt3aWR0aDogMTUlOyB0ZXh0LWRlY29yYXRpb246IGxpbmUtdGhyb3VnaDsiPiBQRVJJTUVURVIgPC90ZD4NCiAgIDx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0O3dpZHRoOiAzNSU7IHRleHQtZGVjb3JhdGlvbjogbGluZS10aHJvdWdoOyI+IERpc3RyaWN0IHBvbHlnb24gcGVyaW1ldGVyIDwvdGQ+DQogIDwvdHI+DQogIDx0cj4NCiAgIDx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0O3dpZHRoOiAxNSU7ICI+IFJFQ09SRF9JRCA8L3RkPg0KICAgPHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQ7d2lkdGg6IDM1JTsgIj4gVW5pcXVlIElEIDwvdGQ+DQogICA8dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdDt3aWR0aDogMTUlOyB0ZXh0LWRlY29yYXRpb246IGxpbmUtdGhyb3VnaDsgIj4gUkVDT1JEX0lEIDwvdGQ+DQogICA8dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdDt3aWR0aDogMzUlOyB0ZXh0LWRlY29yYXRpb246IGxpbmUtdGhyb3VnaDsgIj4gVW5pcXVlIElEIDwvdGQ+DQogIDwvdHI+DQogIDx0cj4NCiAgIDx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0O3dpZHRoOiAxNSU7ICI+IERJU1RSSUNUIDwvdGQ+DQogICA8dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdDt3aWR0aDogMzUlOyAiPiBEaXN0cmljdCBudW1iZXIgMS01NiA8L3RkPg0KICAgPHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQ7d2lkdGg6IDE1JTsgIj4gZGlzdF9jb2RlIDwvdGQ+DQogICA8dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdDt3aWR0aDogMzUlOyAiPiBEaXN0cmljdCBudW1iZXIgMS01NiA8L3RkPg0KICA8L3RyPg0KICA8dHI+DQogICA8dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdDt3aWR0aDogMTUlOyAiPiBOQU1FIDwvdGQ+DQogICA8dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdDt3aWR0aDogMzUlOyAiPiBOYW1lIG9mIGRpc3RyaWN0cyBmcm9tIENyZXNzaWUgKDE5OTMpIDwvdGQ+DQogICA8dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdDt3aWR0aDogMTUlOyAiPiBkaXN0X25hbWUgPC90ZD4NCiAgIDx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0O3dpZHRoOiAzNSU7ICI+IE5hbWUgb2YgZGlzdHJpY3RzIGZyb20gQ3Jlc3NpZSAoMTk5MykgPC90ZD4NCiAgPC90cj4NCiAgPHRyPg0KICAgPHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQ7d2lkdGg6IDE1JTsgIj4gQ09ERSA8L3RkPg0KICAgPHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQ7d2lkdGg6IDM1JTsgIj4gRGlzdHJpY3QgY29kZSBmcm9tIFdpbkJ1Z3MgPC90ZD4NCiAgIDx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0O3dpZHRoOiAxNSU7IHRleHQtZGVjb3JhdGlvbjogbGluZS10aHJvdWdoOyAiPiBDT0RFIDwvdGQ+DQogICA8dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdDt3aWR0aDogMzUlOyB0ZXh0LWRlY29yYXRpb246IGxpbmUtdGhyb3VnaDsgIj4gRGlzdHJpY3QgY29kZSBmcm9tIFdpbkJ1Z3MgPC90ZD4NCiAgPC90cj4NCiAgPHRyPg0KICAgPHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQ7d2lkdGg6IDE1JTsgIj4gQ0FOQ0VSIDwvdGQ+DQogICA8dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdDt3aWR0aDogMzUlOyAiPiBMaXAgY2FuY2VyIGNhc2VzIGZyb20gQ3Jlc3NpZSAoMTk5MykgPC90ZD4NCiAgIDx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0O3dpZHRoOiAxNSU7ICI+IG9ic19jYSA8L3RkPg0KICAgPHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQ7d2lkdGg6IDM1JTsgIj4gTGlwIGNhbmNlciBjYXNlcyBmcm9tIENyZXNzaWUgKDE5OTMpIDwvdGQ+DQogIDwvdHI+DQogIDx0cj4NCiAgIDx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0O3dpZHRoOiAxNSU7ICI+IFBPUCA8L3RkPg0KICAgPHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQ7d2lkdGg6IDM1JTsgIj4gUG9wdWxhdGlvbiB5ZWFycyBhdCByaXNrIGZyb20gQ3Jlc3NpZSAoMTk5MykgPC90ZD4NCiAgIDx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0O3dpZHRoOiAxNSU7ICI+IGRpc3RfcG9wbiA8L3RkPg0KICAgPHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQ7d2lkdGg6IDM1JTsgIj4gUG9wdWxhdGlvbiB5ZWFycyBhdCByaXNrIGZyb20gQ3Jlc3NpZSAoMTk5MykgPC90ZD4NCiAgPC90cj4NCiAgPHRyPg0KICAgPHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQ7d2lkdGg6IDE1JTsgIj4gQ0VYUCA8L3RkPg0KICAgPHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQ7d2lkdGg6IDM1JTsgIj4gRXhwZWN0ZWQgY2FzZXMgZnJvbSBMYXdzb24gZXQgYWwuICgxOTk5KSA8L3RkPg0KICAgPHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQ7d2lkdGg6IDE1JTsgIj4gZXhwX2NhIDwvdGQ+DQogICA8dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdDt3aWR0aDogMzUlOyAiPiBFeHBlY3RlZCBjYXNlcyBmcm9tIFN0ZXJuICZhbXA7IENyZXNzaWUgKDE5OTkpIDwvdGQ+DQogIDwvdHI+DQogIDx0ciBzdHlsZT0iYm9yZGVyLWJvdHRvbToxcHggc29saWQgYmxhY2s7Ij4NCiAgIDx0ZCBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0O3dpZHRoOiAxNSU7ICI+IEFGRiA8L3RkPg0KICAgPHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmxlZnQ7d2lkdGg6IDM1JTsgIj4gT3V0ZG9vciBpbmR1c3RyeSBmcm9tIExhd3NvbiBldCBhbC4gKDE5OTkpIDwvdGQ+DQogICA8dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdDt3aWR0aDogMTUlOyAiPiBwY3RfYWZmIDwvdGQ+DQogICA8dGQgc3R5bGU9InRleHQtYWxpZ246bGVmdDt3aWR0aDogMzUlOyAiPiBPdXRkb29yIGluZHVzdHJ5IGZyb20gU3Rlcm4gJmFtcDsgQ3Jlc3NpZSAoMTk5OSkgPC90ZD4NCiAgPC90cj4NCjwvdGJvZHk+DQo8L3RhYmxlPg0KDQojIyBBaW1zIG9mIHRoaXMgc2Vzc2lvbg0KDQo8ZGl2IHN0eWxlPSJsaW5lLWhlaWdodDoyLjI7Ij4NCjEuICBEb3dubG9hZCBzcGF0aWFsIGJvdW5kYXJpZXMgYW5kIG9ic2VydmVkIGFuZCBleHBlY3RlZCBjYXNlcyBvZiBpbmNpZGVudCBtYWxlIGxpcCBjYW5jZXIgaW4gU2NvdHRpc2ggZGlzdHJpY3RzIGZyb20gMTk3NeKAkzE5ODBcDQoyLiAgQ2FsY3VsYXRlIGFuZCBtYXAgdGhlIHN0YW5kYXJkaXNlZCBpbmNpZGVuY2UgcmF0aW9zIChTSVIpIGFuZCB0aGVpciBwcmVjaXNpb24gZnJvbSB0aGUgcmF3IGRhdGFcDQozLiAgQ3JlYXRlIGEgcXVlZW4gYWRqYWNlbmN5IG1hdHJpeCB0aGF0IGlkZW50aWZpZXMgdGhlIG5laWdoYm91cnMgZm9yIGVhY2ggU2NvdHRpc2ggZGlzdHJpY3Qgc2hhcmluZyBhIGNvbW1vbiBib3VuZGFyeSAoZWRnZSkgb3IgcG9pbnQgKHZlcnRleClcDQo0LiAgRml0IGEgQmVzYWcsIFlvcmsgYW5kIE1vbGxpw6kgKEJZTSkgY29uZGl0aW9uYWwgYXV0b3JlZ3Jlc3NpdmUgKENBUikgbW9kZWwgdG8gcHJvZHVjZSBhIHNtb290aGVkIGRpc2Vhc2UgbWFwIG9mIGxpcCBjYW5jZXIgcmlzayBpbiBTY290bGFuZCBvdmVyIHRoZSBzdHVkeSBwZXJpb2RcDQogICAgNC4xIENhbGN1bGF0ZSBhbmQgbWFwIHJlc2lkdWFsIHJpc2sgZXN0aW1hdGVkIGJ5ICRlXntzX2kgKyB1X2l9JFwNCiAgICA0LjIgRGVjb21wb3NlIGFuZCBtYXAgcmVzaWR1YWwgcmlzayBkdWUgdG8gc3BhdGlhbGx5IHN0cnVjdHVyZWQgJChlXntzX2l9KSQgYW5kIHVuc3RydWN0dXJlZCAkKGVee3VfaX0pJCBlZmZlY3RzXA0KICAgIDQuMyBFc3RpbWF0ZSBwcm9wb3J0aW9uIG9mIHJlc2lkdWFsIHJpc2sgaW4gbWFsZSBsaXAgY2FuY2VyIGluY2lkZW5jZSBkdWUgdG8gc3BhdGlhbCBlZmZlY3RzICRccmhvID0gXHNpZ21hXnsyfV97c30gLyAoXHNpZ21hXnsyfV97c30gKyBcc2lnbWFeezJ9X3t1fSkkXA0KICAgIDQuNCBDYWxjdWxhdGUgcG9zdGVyaW9yIHByb2JhYmlsaXR5IGZvciBpbmNyZWFzZWQgcmVzaWR1YWwgcmlzayBvZiBtYWxlIGxpcCBjYW5jZXIgaW5jaWRlbmNlIGZvciBlYWNoIGRpc3RyaWN0DQo8IS0tIDUuICBGaXQgYSBCWU0gZWNvbG9naWNhbCBDQVIgbW9kZWwgdG8gb2J0YWluIGFuIGVmZmVjdCBlc3RpbWF0ZSBmb3IgdGhlIGFzc29jaWF0aW9uIGJldHdlZW4gbGlwIGNhbmNlciBpbmNpZGVuY2UgYW5kIHRoZSBwZXJjZW50YWdlIG9mIG1hbGUgcG9wdWxhdGlvbiBlbmdhZ2VkIGluIGFncmljdWx0dXJlLCBmaXNoaW5nIGFuZCBmb3Jlc3RyeSAoQUZGKVwgLS0+DQo8IS0tICAgICA1LjEgQ2FsY3VsYXRlIGVmZmVjdCBlc3RpbWF0ZSBhbmQgOTUlIGNyZWRpYmxlIGludGVydmFsIChDckkpIGZvciBBRkYgZXhwb3N1cmUgY292YXJpYXRlXCAtLT4NCjwhLS0gICAgIDUuMSBDYWxjdWxhdGUgYW5kIG1hcCByZXNpZHVhbCByaXNrIGVzdGltYXRlZCBieSAkZV57c19pICsgdV9pfSRcIC0tPg0KPCEtLSAgICAgNS4yIERlY29tcG9zZSBhbmQgbWFwIHJlc2lkdWFsIHJpc2sgZHVlIHRvIHNwYXRpYWxseSBzdHJ1Y3R1cmVkIGFuZCB1bnN0cnVjdHVyZWQgZWZmZWN0c1wgLS0+DQo8IS0tICAgICA1LjMgRXZhbHVhdGUgY2hhbmdlIGluICQoXHJobykkIGFmdGVyIGFkanVzdGluZyBmb3IgdGhlIHBlcmNlbnRhZ2Ugb2YgbWFsZSBwb3B1bGF0aW9uIGluIEFGRlwgLS0+DQo8IS0tICAgICA1LjQgQ2FsY3VsYXRlIChwb3N0ZXJpb3IpIHByb2JhYmlsaXR5IG9mIGluY3JlYXNlZCBsaXAgY2FuY2VyIHJpc2sgZm9yIGVhY2ggZGlzdHJpY3QgYWZ0ZXIgYWRqdXN0aW5nIGZvciBBRkZcIC0tPg0KPCEtLSA2LiAgQ29tcGFyZSBjaGFuZ2VzIGluIHJlc2lkdWFsIHZhcmlhbmNlIGR1ZSB0byBzcGF0aWFsbHkgc3RydWN0dXJlZCBhbmQgdW5zdHJ1Y3R1cmVkIGZhY3RvcnMgZnJvbSA0IHRvIDUgLS0+DQo8L2Rpdj4NCg0KIyMgUHJlbGltaW5hcmllcw0KDQpgYGB7ciBvcHRpb25zLCBpbmNsdWRlID0gRkFMU0V9DQoNCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCg0Ka25pdHI6Om9wdHNfY2h1bmskYXBwZW5kKGF0dHIuc291cmNlID0gJy5udW1iZXJMaW5lcycsDQogICAgICAgICAgICAgICAgICAgICAgICAgY2xhc3Muc291cmNlID0gIi50ZXh0UHJlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICBjbGFzcy5vdXRwdXQgPSAiLnRleHRQcmUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGF0dHIub3V0cHV0ID0gJy5udW1iZXJMaW5lcycpDQoNCmJhc2U6Om9wdGlvbnMod2lkdGggPSAxNzApDQoNCiMgQ29udmllbmNlIGZ1bmN0aW9uIGZvciBjb252ZXJ0aW5nIGJldHdlZW4gcGl4ZWxzIGFuZCBpbmNoZXMNCg0KcHgyaW4gPC0gZnVuY3Rpb24odmFsdWUgPSBOQSwgbWV0cmljID0gImluIil7DQogIA0KICAjIHZhbHVlICAgbnVtZXJpYyB2YWx1ZSB0byBjb252ZXJ0DQogICMgbWV0cmljICBjaGFyYWN0ZXIgdmFsdWUgYygicHgiLCAiaW4iKSBpbmRpY2F0ZSB1bml0IHR5cGUgb2YgdmFsdWUNCg0KICBiYXNlOjpyZXR1cm4oYmFzZTo6aWZlbHNlKG1ldHJpYyA9PSAicHgiLCB2YWx1ZSAvIDk2LCB2YWx1ZSAqIDk2KSkNCiAgDQogICMgRXhhbXBsZXMNCiAgDQogICMgUGl4ZWxzIHRvIGluY2hlczogcHgyaW4oMTQ0MCwgInB4IikNCiAgIyBJbmNoZXMgdG8gcGl4ZWxzOiBweDJpbiggIDE1LCAiaW4iKQ0KICANCn0NCg0KYGBgDQoNCiMjIyBSZXF1aXJlZCBwYWNrYWdlcw0KDQpUaGVzZSBhcmUgdGhlIHBhY2thZ2VzIHRoYXQgbmVlZCB0byBiZSBpbnN0YWxsZWQgYW5kIGF0dGFjaGVkIHRvIGNvbXBsZXRlIHRoZSBhbmFseXNpcy4NCg0KYGBge3IgcmVxdWlyZWR9DQoNCnsgIyBDaGVjayBmb3IgYW5kIGluc3RhbGwgcGFjbWFuIHBhY2thZ2UgaWYgbWlzc2luZw0KICANCiAgaWYoYmFzZTo6cmVxdWlyZShwYWNtYW4sIHF1aWV0bHkgPSBUUlVFKSA9PSBGQUxTRSl7aW5zdGFsbC5wYWNrYWdlcygicGFjbWFuIil9DQogIA0KICAjIGxpc3QgcmVxdWlyZWQgcGFja2FnZXMNCiAgDQogIHJlcVBhY2thZ2VzIDwtIGMoInRpZHl2ZXJzZSIsICAgICAgIyBBbiBvcGluaW9uYXRlZCBjb2xsZWN0aW9uIG9mIFIgcGFja2FnZXMgZGVzaWduZWQgZm9yIGRhdGEgc2NpZW5jZQ0KICAgICAgICAgICAgICAgICAgICJDQVJCYXllcyIsICAgICAgICMgU3BhdGlhbCBHZW5lcmFsaXNlZCBMaW5lYXIgTWl4ZWQgTW9kZWxzIGZvciBBcmVhbCBVbml0IERhdGENCiAgICAgICAgICAgICAgICAgICAiY29kYSIsICAgICAgICAgICAjIEEgcGFja2FnZSBmb3IgT3V0cHV0IEFuYWx5c2lzIGFuZCBEaWFnbm9zdGljcyBmb3IgTUNNQw0KICAgICAgICAgICAgICAgICAgICJlcGl0b29scyIsICAgICAgICMgQSBwYWNrYWdlIGZvciBlcGlkZW1pb2xvZ2ljYWwgYW5hbHlzaXMNCiAgICAgICAgICAgICAgICAgICAiZ2dtY21jIiwgICAgICAgICAjIE1DTUMgZGlhZ25vc3RpY3Mgd2l0aCBnZ3Bsb3QNCiAgICAgICAgICAgICAgICAgICAiZ2dwdWJyIiwgICAgICAgICAjIEEgcGFja2FnZSBmb3IgcHJvZHVjaW5nIHB1YmxpY2F0aW9uLXJlYWR5IHBsb3RzIA0KICAgICAgICAgICAgICAgICAgICJnZ3JlcGVsIiwgICAgICAgICMgQSBwYWNrYWdlIGZvciBwb3NpdGlvbiBub24tb3ZlcmxhcHBpbmcgdGV4dCBsYWJlbHMgd2l0aCAnZ2dwbG90MicNCiAgICAgICAgICAgICAgICAgICAiR0dhbGx5IiwgICAgICAgICAjIEEgcGFja2FnZSB0byBkbyBwYWlycGxvdHMNCiAgICAgICAgICAgICAgICAgICAia25pdHIiLCAgICAgICAgICAjIEEgZ2VuZXJhbC1wdXJwb3NlIHRvb2wgZm9yIGR5bmFtaWMgcmVwb3J0IGdlbmVyYXRpb24gaW4gUg0KICAgICAgICAgICAgICAgICAgICJuaW1ibGUiLCAgICAgICAgICMgQSBwYWNrYWdlIGZvciBwZXJmb3JtaW5nIE1DTUMgaW4gUg0KICAgICAgICAgICAgICAgICAgICJwYXRjaHdvcmsiLCAgICAgICMgQSBwYWNrYWdlIHRvIGNvbWJpbmUgcGxvdHMNCiAgICAgICAgICAgICAgICAgICAicm1hcmtkb3duIiwgICAgICAjIEEgcGFja2FnZSBmb3IgY3JlYXRpbmcgZHluYW1pYyBkb2N1bWVudHMgZm9yIFINCiAgICAgICAgICAgICAgICAgICAiUkNvbG9yQnJld2VyIiwgICAjIEEgcGFja2FnZSBvZiBjb2xvdXIgcGFsZXR0ZXMNCiAgICAgICAgICAgICAgICAgICAic2NhbGVzIiwgICAgICAgICAjIFNjYWxlIGZ1bmN0aW9ucyBmb3IgdmlzdWFsaXphdGlvbg0KICAgICAgICAgICAgICAgICAgICJzZiIsICAgICAgICAgICAgICMgU2ltcGxlIGZlYXR1cmVzIGZvciBSDQogICAgICAgICAgICAgICAgICAgInNwZGVwIikgICAgICAgICAgIyBBIHBhY2thZ2UgdG8gY2FsY3VsYXRlIG5laWdoYm9ycykNCiAgDQogICMgTG9hZCAoYW5kIGluc3RhbGwgaWYgbWlzc2luZykgb3RoZXIgcmVxdWlyZWQgcGFja2FnZXMNCiAgDQogIHBhY21hbjo6cF9sb2FkKGNoYXIgPSByZXFQYWNrYWdlcywgaW5zdGFsbCA9IFRSVUUpDQogIA0KICAjIENoZWNrIHJlcXVpcmVkIHBhY2thZ2VzIGFyZSBsb2FkZWQNCiAgDQogIHBhY21hbjo6cF9sb2FkZWQoY2hhciA9IHJlcVBhY2thZ2VzKQ0KICANCn0NCg0KYGBgDQoNCiMjIyBSIGVudmlyb25tZW50DQoNClRoaXMgb3V0cHV0IHNob3dzIHRoZSBgUmAgZW52aXJvbm1lbnQgb2YgdGhlIGFuYWx5c2lzOyBpdCBpbmNsdWRlcyBkZXBlbmRlbmNpZXMgbG9hZGVkIC8gYXR0YWNoZWQgYnkgcGFja2FnZXMgYWJvdmUuDQoNCmBgYHtyIGVudmlyb24sIGNsYXNzLm91dHB1dD0iLnRleHRQcmUgLnNjcm9sbC0xMDAifQ0KDQojIEdldCBzZXNzaW9uIGluZm9ybWF0aW9uDQoNCnV0aWxzOjpzZXNzaW9uSW5mbygpDQoNCmBgYA0KDQojIyBEYXRhDQoNCkluIHRoaXMgc2VjdGlvbiB3ZSBleHRyYWN0LCB0cmFuc2Zvcm0gYW5kIGxvYWQgKEVUTCkgdGhlIGxpcCBjYW5jZXIgZGF0YS4gVGhpcyBjYW4gYmUgZG9uZSBtYW51YWxseSwgYnV0IHRoZSBmb2xkZWQgY29kZSBjaHVuayBzaG93IGhvdyBpdCBjYW4gYmUgZG9uZSBlbnRpcmVseSB3aXRoaSBgUmAuDQoNCiMjIyBEb3dubG9hZCBkYXRhDQoNClRoZSBmb2xsb3dpbmcgb3V0cHV0IHNlY3Rpb24gc2hvd3MgYWxsIHRoZSBmaWxlcyBjb250YWluZWQgaW4gdGhlIEdlb0RhIENlbnRlciBaSVAgZmlsZSB3ZSBkb3dubG9hZGVkIHVzaW5nIHRoZSBmb2xkZWQgKipDb2RlKiogY2h1bmsuIFdlIHdpbGwgdXNlIHRoZSBgc2NvdGxpcC9zY290bGlwLmdwa2dgIEdlb1BhY2thZ2UgZGF0YSBmaWxlIHdpdGggcmVjb3JkIGluZGV4IDc5IGF0IHJvdyA0MCBmb3Igb3VyIGFuYWx5c2lzLiANCg0KYGBge3IgZG93bmxvYWQtZGF0YX0NCg0KIyBEb3dubG9hZCBTY290dGlzaCBsaXAgY2FuY2VyIGRhdGEgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyBBdmFpbGFibGUgZnJvbSB0aGUgdGhlIEdlb0RhIENlbnRlciBhcyBhIHppcHBlZCBhcmNoaXZlIGZyb206DQojIGh0dHBzOi8vZ2VvZGFjZW50ZXIuZ2l0aHViLmlvL2RhdGEtYW5kLWxhYi9zY290bGlwLyBidXQgY2FuIGJlIGRvd25sb2FkZWQNCiMgZGlyZWN0bHkgd2l0aGluIFINCg0KIyBEb3dubG9hZCBaSVAgZmlsZSB0byB0ZW1wIGRpcmVjdG9yeQ0KDQpkYXRhLnVybCA8LSAiaHR0cHM6Ly9nZW9kYWNlbnRlci5naXRodWIuaW8vZGF0YS1hbmQtbGFiL2RhdGEvc2NvdGxpcC56aXAiDQoNCnV0aWxzOjpkb3dubG9hZC5maWxlKGRhdGEudXJsLA0KICAgICAgICAgICAgICAgICAgICAgYmFzZTo6ZmlsZS5wYXRoKGJhc2U6OnRlbXBkaXIoKSwgInNjb3RsaXAuemlwIiksDQogICAgICAgICAgICAgICAgICAgICBtb2RlID0gIndiIikNCg0KIyBWaWV3IHRoZSBjb250ZW50cyBvZiB0aGUgemlwIGZpbGUNCg0KdXRpbHM6OnVuemlwKHppcGZpbGUgPSBiYXNlOjpmaWxlLnBhdGgoYmFzZTo6dGVtcGRpcigpLCAic2NvdGxpcC56aXAiKSwgbGlzdCA9IFRSVUUpICU+JQ0KICAgICAgICAgICAgICBiYXNlOjphcy5kYXRhLmZyYW1lKCkgJT4lDQogICAgICAgICAgICAgIGFycmFuZ2UoTmFtZSkgJT4lDQogIGRwbHlyOjpwdWxsKE5hbWUpDQoNCmBgYA0KDQojIyMgRXh0cmFjdCBkYXRhDQoNCkEgR2VvUGFja2FnZSBpcyBhbiBvcGVuLXNvdXJjZSwgc3RhbmRhcmRzLWJhc2VkIGFuZCBwbGF0Zm9ybSBpbmRlcGVuZGVudCBmaWxlIGZvcm1hdCBmb3Igc3RvcmluZyBib3RoIHNwYXRpYWwgYW5kIGF0dHJpYnV0ZSBkYXRhIGluIGEgc2luZ2xlLCBwb3J0YWJsZSBmaWxlLiBJbiB0aGlzIGNvZGUgY2h1bmssIHdlIGV4dHJhY3QgdGhlIEdlb1BhY2thZ2UgYW5kIHRoZW4gcXVlcnkgaXQgdG8gaWRlbnRpZnkgdGhlIGNvcnJlY3QgY29ycmVjdCBkYXRhIGxheWVyIHRvIHVzZS4gIA0KDQpgYGB7ciBleHRyYWN0LWRhdGF9DQoNCiMjIEV4dHJhY3QgdGhlIHNjb3RsaXAuZ3BrZyBnZW9wYWNrYWdlIGRhdGEgZmlsZSAocm93IDc5KSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCiMgU2VlIGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0dlb1BhY2thZ2UgZm9yIGEgZGVzY3JpcHRpb24gb2YgdGhlIA0KIyBnZW9wYWNrYWdlIGRhdGEgZm9ybWF0LiANCg0KIyBFeHRyYWN0IHRoZSBzY290bGlwLmdwa2cgZ2VvcGFja2FnZSBmcm9tIHRoZSBaSVAgZmlsZQ0KDQp1dGlsczo6dW56aXAoemlwZmlsZSA9IGJhc2U6OmZpbGUucGF0aChiYXNlOjp0ZW1wZGlyKCksICJzY290bGlwLnppcCIpLA0KICAgICAgICAgICAgIGZpbGVzID0gInNjb3RsaXAvc2NvdGxpcC5ncGtnIiwNCiAgICAgICAgICAgICBleGRpciA9IGJhc2U6OnRlbXBkaXIoKSwNCiAgICAgICAgICAgICBqdW5rcGF0aHMgPSBUUlVFKSAjIE9ubHkgdXNlIHRoZSBmaWxlIG5hbWUgb2YgdGhlIHN0b3JlZCBmaWxlIHBhdGggd2hlbiBleHRyYWN0aW5nDQoNCiMgTGlzdCBHZW9QYWNrIGxheWVycw0KDQpiYXNlOjpjYXQoIkxpc3QgR2VvUGFja2FnZSBsYXllcnM6IiwNCiAgICAgICAgICAiXG5cbiIsDQogICAgICAgICAgYmFzZTo6YXMuY2hhcmFjdGVyKGJhc2U6OmRhdGEuZnJhbWUobGF5ZXJzID0gc2Y6OnN0X2xheWVycyhiYXNlOjpmaWxlLnBhdGgoYmFzZTo6dGVtcGRpcigpLCAic2NvdGxpcC5ncGtnIikpJG5hbWUpKSkNCg0KYGBgDQoNCiMjIyBMb2FkIGRhdGENCg0KQXMgdGhlIEdlb1BhY2thZ2UgY29udGFpbnMgYSBzaW5nbGUgbGF5ZXIgKHNjb3RsaXApLCB3ZSByZWFkIHRoaXMgaW50byBgUmAsIG9ubHkgdG8gYmUgZGlzYXBwb2ludGVkIHRoYXQgdGhlIHdyb25nIGNvb3JkaW5hdGUgcmVmZXJlbmNlIHN5c3RlbSAoV0dTIDgwKSBoYXMgYmVlbiBhc3NpZ25lZCB0byB0aGUgc3BhdGlhbCBkYXRhLiBUaGUgY29ycmVjdCBwcm9qZWN0ZWQgY29vcmRpbmF0ZSByZWZlcmVuY2Ugc3lzdGVtIGZvciB0aGVzZSBkYXRhIGFyZSBbT1NHQjM2IC8gQnJpdGlzaCBOYXRpb25hbCBHcmlkXShodHRwczovL2Vwc2cuaW8vMjc3MDApLCB3aGljaCB3ZSBuZWVkIHRvIGFwcGx5IG1hbnVhbGx5Lg0KDQpgYGB7ciBsb2FkLWRhdGF9DQoNCiMgUmVhZCBzY290bGlwLmdwa2cgbGF5ZXIsIHdoaWNoIGluY2x1ZGVzIGRhdGEgYW5kIGdlb21ldHJ5Lg0KDQojIE5vdGU6IEkgaGF2ZSBzZXQgdGhlIGNvb3JkaW5hdGUgcmVmZXJlbmNlIHN5c3RlbSAoQ1JTKSB0byBOQSBiZWNhdXNlIHRoZSBDUlMNCiMgICAgICAgc3VwcGxpZWQgaW4gdGhlIGdlb3BhY2sgKFdHUyA4MCkgaXMgaW5jb3JyZWN0LllvdSBjYW4gZWFzaWx5IHRlbGwgdGhpcyANCiMgICAgICAgYnkgbG9va2luZyBhdCBoZSBib3VuZGluZyBib3ggdmFsdWVzLiBXR1MgODAgaXMgYSBnZW9ncmFwaGljIGNvb3JkaW5hdGUNCiMgICAgICAgc3lzdGVtIHdpdGggZGVjaW1hbCBkZWdyZWUgdW5pdHMsIHNvIGJvdGggdGhlIG1pbmltYSBub3IgbWF4aW1hIHZhbHVlcw0KIyAgICAgICBhcmUgYm91bmRlZCBieSAtMTgwIHRvICsxODAgZGVncmVlcy4gVGhlIHZhbHVlcyBoZXJlIGFyZSBhbGwgZ3JhdGVyIHRoYW4NCiMgICAgICAgNDUwLDAwMCwgd2hpY2ggaW5kaWNhdGUgYSBwcm9qZWN0ZWQgY29vcmRpbmF0ZSBzeXN0ZW0gb2YgZWFzdGluZyBhbmQNCiMgICAgICAgbm9ydGhpbmcgaW4gbGluZWFyIG1ldGVycw0KDQpzcmNfc2YgPC0gc2Y6OnN0X3JlYWQoZHNuID0gYmFzZTo6ZmlsZS5wYXRoKGJhc2U6OnRlbXBkaXIoKSwgInNjb3RsaXAuZ3BrZyIpLA0KICAgICAgICAgICAgICAgICAgICAgIGxheWVyID0gInNjb3RsaXAiLA0KICAgICAgICAgICAgICAgICAgICAgIGNycyA9IE5BX2Nyc18pICMgUmVtb3ZlIHRoZSB3cm9uZyBjb29yZGluYXRlIHJlZmVyZW5jZSBzeXN0ZW0gKENSUykgYXNzaWduZWQgaW4gdGhlIGdlb3BhY2thZ2UNCg0KIyBBZnRlciBzb21lIGZvc3NpY2tpbmcgYXJvdW5kLCBJIHdhcyBhYmxlIHRvIGRldGVybWluZSB0aGUgY29ycmVjdCBwcm9qZWN0ZWQgY29vcmRpbmF0ZQ0KIyBzeXN0ZW0gZm9yIHRoZXNlIGRhdGEgaXMgT1NHQjM2IC8gQnJpdGlzaCBOYXRpb25hbCBHcmlkLCB3aGljaCB3ZSBub3cgYXBwbHkgdXNpbmcNCiMgdGhlIEV1cm9wZWFuIFBldHJvbGV1bSBTdXJ2ZXkgR3JvdXAgKEVQU0cpIGNvZGUgMjc3MDAgDQoNCnNmOjpzdF9jcnMoc3JjX3NmKSA8LSAyNzcwMCAjIHNlZSBodHRwczovL2Vwc2cuaW8vMjc3MDAgZm9yIENSUyBkZXRhaWxzDQoNCiMgQ2hlY2sgdGhhdCB0aGUgQ1JTIGhhcyBiZWVuIGFwcGxpZWQgdG8gdGhlIHNwYXRpYWwgZGF0YSANCg0KcHJpbnQoc3JjX3NmKQ0KDQpgYGANCg0KIyMjIEVucmljaCBkYXRhDQoNCkluIHRoaXMgZmluYWwgcHJlcGFyYXRpb24gc3RlcCwgd2Ugd3JhbmdsZSB0aGUgcmVtYWluaW5nIGF0dHJpYnV0ZSBkYXRhIChlLmcuIHNvbWUgZGlzdHJpY3QgbmFtZXMgbmVlZCB0aWR5aW5nIHVwKSBpbnRvIGFuIGludHVpdGl2ZSBhbmFseXNpcy1yZWFkeSBmb3JtYXQgYW5kIGVucmljaCBpdCBieSBhZGRpbmcgc3RhbmRhcmRpc2VkIGluY2lkZW5jZSByYXRpb3MgYW5kIHRoZWlyIGV4YWN0IFBvaXNzb24gOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzLiBXZSB3aWxsIGFsc28gY2FsY3VsYXRlIGluZGljaWVzIG9mIGVzdGltYXRlIHByZWNpc2lvbiBiYXNlZCBvbiBleHBlY3RlZCBhbmQgb2JzZXJ2ZWQgbGlwIGNhbmNlciBjYXNlcy4NCg0KYGBge3IgZW5yaWNoLWRhdGF9DQoNCiMgQ2xlYW4gYW5kIGVucmljaCBzZiBmb3IgZGF0YSBhbmFseXNpcw0KDQpsaXBfc2YgPC0gc3JjX3NmICU+JQ0KICANCiAgIyBSZW5hbWUgY29sdW1ucyB0byBsb3dlciBjYXNlDQogIA0KICBkcGx5cjo6cmVuYW1lX3dpdGgoYmFzZTo6dG9sb3dlcikgJT4lDQogIA0KICAjIExpbWl0IHRvIHNlbGVjdGVkIChyZW5hbWVkKSB2YXJpYWJsZXMNCiAgDQogIGRwbHlyOjpzZWxlY3QoZGlzdF9jb2RlID0gZGlzdHJpY3QsIGRpc3RfbmFtZSA9IG5hbWUsIGRpc3RfcG9wbiA9IHBvcCwgb2JzX2NhID0gY2FuY2VyLCBleHBfY2EgPSBjZXhwLCBwY3RfYWZmID0gYWZmKSAlPiUNCiAgDQogICMgQ29ycmVjdCB0eXBvZ3JhcGhpY2FsIGVycm9ycyBpbiBkaXN0cmljdCBuYW1lcw0KICANCiAgZHBseXI6Om11dGF0ZShkcGx5cjo6YWNyb3NzKGRpc3RfbmFtZSwgfiBkcGx5cjo6Y2FzZV93aGVuKC4gPT0gIkVhc3RLaWxicmlkZSIgfiAiRWFzdCBLaWxicmlkZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuID09ICJFYXN0TG90aGlhbiIgfiAiRWFzdCBMb3RoaWFuIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4gPT0gIk5FRmlmZSIgfiAiTkUgRmlmZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuID09ICJXZXN0ZXJuSXNsZXMiIH4gIldlc3Rlcm4gSXNsZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLiA9PSAiV2VzdExvdGhpYW4iIH4gIldlc3QgTG90aGlhbiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZGVmYXVsdCA9IC4pKSkgJT4lDQogIA0KICAjIENhbGN1bGF0ZSBzdGFuZGFyZGlzZWQgaW5jaWRlbmNlIHJhdGlvcyAoU0lSKSB3aXRoIGV4YWN0IFBvaXNzb24gOTUlIA0KICAjIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIHVzaW5nIHVzaW5nIHBvaXMuZXhhY3QgZnVuY3Rpb24gZnJvbSBlcGl0b29scy4NCiAgDQogIGRwbHlyOjpiaW5kX2NvbHMoYmFzZTo6ZGF0YS5mcmFtZShlcGl0b29sczo6cG9pcy5leGFjdChwdWxsKC4sIG9ic19jYSksIHB1bGwoLiwgZXhwX2NhKSkgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRwbHlyOjpzZWxlY3Qob2JzX3Npcl9lc3QgPSByYXRlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ic19zaXJfbDk1ID0gbG93ZXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2JzX3Npcl91OTUgID0gdXBwZXIpKSkgJT4lDQogIA0KICAjIENhbGN1bGF0ZSBwcm9iYWJpbGl0eSB2YWx1ZXMgZm9yIFNJUg0KICANCiAgZHBseXI6Om11dGF0ZShvYnNfc2lyX3NpZyA9IHN0YXRzOjpkcG9pcyhvYnNfY2EsIGV4cF9jYSksDQogICAgICAgICAgICAgICAgb2JzX3Npcl9jYXQgPSBkcGx5cjo6Y2FzZV93aGVuKG9ic19zaXJfZXN0IDwgMSAmIG9ic19zaXJfc2lnIDwgMC4wMDUgfiAiLS0iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvYnNfc2lyX2VzdCA8IDEgJiBvYnNfc2lyX3NpZyA8IDAuMDI1IH4gIi0iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvYnNfc2lyX2VzdCA+IDEgJiBvYnNfc2lyX3NpZyA8IDAuMDA1IH4gIisrIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2JzX3Npcl9lc3QgPiAxICYgb2JzX3Npcl9zaWcgPCAwLjAyNSB+ICIrIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmRlZmF1bHQgPSAiIikpICU+JQ0KICANCiAgIyBDYWxjdWxhdGUgc3RhbmRhcmQgYW5kIHJlbGF0aXZlIGVycm9ycyBmb3IgU0lSDQogIA0KICBkcGx5cjo6bXV0YXRlKG9ic19zaXJfc2UgPSBiYXNlOjpzcXJ0KG9ic19jYSkgLyBleHBfY2EsDQogICAgICAgICAgICAgICAgb2JzX3Npcl9yc2UgPSBvYnNfc2lyX3NlIC8gb2JzX3Npcl9lc3QsICAgIyBBbHNvIGVzdGltYXRlZCBieSBSU0UgPSAxIC8gYmFzZTo6c3FydChvYnNfY2EpLA0KICAgICAgICAgICAgICAgIGV4cF9zaXJfcnNlID0gMSAvIGV4cF9jYSkgJT4lDQogIA0KICAjICMgQWRkIGRpc3RyaWN0IGNlbnRyb2lkcyAobm90ZSB1c2Ugb2Ygc2Y6OnN0X2dlb21ldHJ5IC0gYXZvaWRzIHdhcm5pbmdzIGFib3V0IGFzc3VtZWQgYXR0cmlidXRlIGRpc3RyaWJ1dGlvbnMNCiAgIyANCiAgIyBkcGx5cjo6YmluZF9jb2xzKHNmOjpzdF9jb29yZGluYXRlcyhzZjo6c3RfY2VudHJvaWQoc2Y6OnN0X2dlb21ldHJ5KC4pKSkgJT4lDQogICMgICAgICAgICAgICAgICAgICAgIGJhc2U6OmFzLmRhdGEuZnJhbWUoKSAlPiUNCiAgIyAgICAgICAgICAgICAgICAgICAgZHBseXI6OnJlbmFtZShjZW50cm9pZF94ID0gWCwgY2VudHJvaWRfeSA9IFkpKSAlPiUNCiAgDQogICMgQWRkIHZhcmlhYmxlIGxhYmVscw0KICANCiAgbGFiZWxsZWQ6OnNldF92YXJpYWJsZV9sYWJlbHMoZGlzdF9jb2RlID0gIkRpc3RyaWN0IGNvZGUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXN0X25hbWUgPSAiRGlzdHJpY3QgbmFtZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpc3RfcG9wbiA9ICJNYWxlIHBvcHVsYXRpb24geWVhcnMgYXQgcmlzayAoMTk3NS0xOTgwKSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ic19jYSA9ICJPYnNlcnZlZCBtYWxlIGxpcCBjYW5jZXIgY2FzZXMgKDE5NzUtMTk4MCkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHBfY2EgPSAiRXhwZWN0ZWQgbWFsZSBsaXAgY2FuY2VyIGNhc2VzICgxOTc1LTE5ODApIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGN0X2FmZiA9ICJQZXJjZW50IG9mIG1hbGUgcG9wdWxhdGlvbiB3b3JraW5nIGluIGFncmljdWx0dXJlLCBmaXNoaW5nIG9yIGZvcmVzdHJ5IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2JzX3Npcl9lc3QgPSAiT2JzZXJ2ZWQgU0lSIGVzdGltYXRlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2JzX3Npcl9sOTUgPSAiT2JzZXJ2ZWQgU0lSIGxvd2VyIDk1JSBDSSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ic19zaXJfdTk1ID0gIk9ic2VydmVkIFNJUiB1cHBlciA5NSUgQ0kiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvYnNfc2lyX3NpZyA9ICJQcm9iYWJpbGl0eSB2YWx1ZSBmb3Igb2JzZXJ2ZWQgU0lSIGVzdGltYXRlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2JzX3Npcl9jYXQgPSAiUHJvYmFiaWxpdHkgY2F0ZWdvcnkgZm9yIG9ic2VydmVkIFNJUiBlc3RpbWF0ZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ic19zaXJfc2UgPSAiT2JzZXJ2ZWQgU0lSIHN0YW5kYXJkIGVycm9yIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2JzX3Npcl9yc2UgPSAiT2JzZXJ2ZWQgU0lSIHJlbGF0aXZlIHN0YW5kYXJkIGVycm9yIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhwX3Npcl9yc2UgPSAiUHJvcG9ydGlvbmFsIHByZWNpc2lvbiBvZiBTSVIgZnJvbSBleHBlY3RlZCBjYXNlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgY2VudHJvaWRfeCA9ICJDZW50cm9pZCBYIGNvb3JkaW5hdGUgKEVQU0c6Mjc3MDApIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBjZW50cm9pZF95ID0gIkNlbnRyb2lkIFkgY29vcmRpbmF0ZSAoRVBTRzoyNzcwMCkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tID0gIkdlb21ldHJ5IChPU0dCIDE5MzYgLyBCcml0aXNoIE5hdGlvbmFsIEdyaWQpIikgJT4lDQogIA0KICAjIE1vdmUgZ2VvbWV0cnkgY29sdW1uIHRvIGVuZCBvZiBkYXRhIHNldA0KICANCiAgZHBseXI6OnNlbGVjdChkcGx5cjo6ZXZlcnl0aGluZygpLCAtZ2VvbSwgZ2VvbSkNCg0KIyBWaWV3IHRoZSBkYXRhIHNldA0KDQpwcmludChsaXBfc2YsIGRpZ2l0cyA9IDIsIG4gPSA1NikNCg0KYGBgDQoNCiMjIEFuYWx5c2lzDQoNCkp1c3QgYmVmb3JlIHdlIGp1bXAgaW50byB0aGUgYW5hbHlzaXMsIEkgd2lsbCBjcmVhdGUgdGhyZWUgYWRkaXRpb25hbCByZXNvdXJjZXM6DQoNCjEuIEEgU2NvdGxhbmQgYm91bmRhcnkgbGF5ZXIgZm9yIGFubm90YXRpbmcgb3VyIG1hcHMNCg0KYGBge3Igc2N0LWJvdW5kYXJ5fQ0KDQojIERpc3NvbHZlICh1bmlvbikgb3ZlciB0aGUgZGlzdHJpY3QgZ2VvbWV0cmllcyBpbiB0aGUgbGlwX3NmIHNmIG9iamVjdCB0byBvYnRhaW4gIA0KIyBhbiBvdXRsaW5lIChjb3VudHJ5KSBib3VuZGFyeSBmb3IgU2NvdGxhbmQNCg0Kc2N0X3NmIDwtIGxpcF9zZiAlPiUNCiAgZHBseXI6Om11dGF0ZShjb3VudHJ5ID0gIlNjb3RsYW5kIikgJT4lDQogIGRwbHlyOjpzdW1tYXJpc2UoZ2VvbSA9IHNmOjpzdF91bmlvbihnZW9tKSwNCiAgICAgICAgICAgICAgICAgIC5ieSA9IGNvdW50cnkpDQoNCg0KYmFzZTo6cHJpbnQoc2N0X3NmKQ0KDQpgYGANCjIuIEEgbGlzdCBvZiBkaXN0cmljdHMgbGFiZWxzIHRvIGV4Y2x1ZGUgZnJvbSBtYXBzIHRvIHJlZHVjZSB2aXN1YWwgbm9pc2UNCg0KYGBge3IgZGlzdC1leGNsdWRlZH0NCg0KIyBDcmVhdGUgYSB2ZWN0b3Igb2YgZGlzdHJpY3QgbmFtZXMgdG8gZXhjbHVkZSB3aGVuIGxhYmVsaW5nIG1hcHMNCg0KZXhjX2xhYmVscyA8LSBjKCJFYXN0d29vZCIsDQogICAgICAgICAgICAgICAgIktpbG1hcm5vY2siLA0KICAgICAgICAgICAgICAgICJNb25rbGFuZHMiLA0KICAgICAgICAgICAgICAgICJNb3RoZXJ3ZWxsIiwNCiAgICAgICAgICAgICAgICAiUmVuZnJldyIsDQogICAgICAgICAgICAgICAgIkVhc3QgS2lsYnJpZGUiLA0KICAgICAgICAgICAgICAgICJDdW1iZXJuYXVsZCIsDQogICAgICAgICAgICAgICAgIktpcmtjYWxkeSIsDQogICAgICAgICAgICAgICAgIldlc3QgTG90aGlhbiIsDQogICAgICAgICAgICAgICAgIkludmVyY2x5ZGUiLA0KICAgICAgICAgICAgICAgICJTdHJhdGhrZWx2aW4iLA0KICAgICAgICAgICAgICAgICJCZWFyc2RlbiIsDQogICAgICAgICAgICAgICAgIkVhc3QgTG90aGlhbiIsDQogICAgICAgICAgICAgICAgIk1pZGxvdGhpYW4iKQ0KDQpgYGANCg0KMy4gQSBjb2xvdXIgcmFtcCB3aXRoIGxvdywgbWVkaXVtIGFuZCBoaWdoIHZhbHVlcyB0byBhbm5vdGF0ZSBnZ3Bsb3QyIHNjYWxlIGVsZW1lbnRzDQoNCmBgYHtyIGNvbG91ci1yYW1wLCBmaWcuaGVpZ2h0PTEsIGZpZy53aWR0aD1weDJpbigxNDQwLCAicHgiKX0NCg0KIyBWaXN1YWxpemF0aW9uIGNvbG91ciBwYWxldHRlDQoNCmNvbF9wYWwgPC0gYygibG93IiA9IFJDb2xvckJyZXdlcjo6YnJld2VyLnBhbCgxMSwgIlJkWWxCdSIpWzExXSwNCiAgICAgICAgICAgICAibWlkIiA9IFJDb2xvckJyZXdlcjo6YnJld2VyLnBhbCgxMSwgIlJkWWxCdSIpWzZdLA0KICAgICAgICAgICAgICJoaWdoIiA9IFJDb2xvckJyZXdlcjo6YnJld2VyLnBhbCgxMSwgIlJkWWxCdSIpWzFdKQ0KDQojIENyZWF0ZSBhIGNvbG91ciByYW1wIGJhc2VkIG9uIGNvbG91ciBwYWxldHRlDQoNCnJhbXBDb2xvdXJzIDwtIGdyRGV2aWNlczo6Y29sb3JSYW1wUGFsZXR0ZShjb2xfcGFsKQ0KDQojIFZpc3VhbGlzZSB0aGUgY29sb3VyIHBhbGV0dGUNCg0KZ3JhcGhpY3M6OnBhcihtYXIgPSBjKDAsIDAsIDAsIDApKQ0KDQpncmFwaGljczo6aW1hZ2UoYmFzZTo6c2VxKDEsIDEwMDApLCAxLCBiYXNlOjptYXRyaXgoc2VxKDEsMTAwMCksIDEwMDAsMSksIA0KICAgICAgICAgICAgICAgIGNvbCA9IHJhbXBDb2xvdXJzKDEwMDApLA0KICAgICAgICAgICAgICAgIHBpbiA9IGMoMSwgNSksDQogICAgICAgICAgICAgICAgYXhlcyA9IEZBTFNFLA0KICAgICAgICAgICAgICAgIGFubiA9IEZBTFNFKQ0KDQpgYGANCg0KIyMjIE9ic2VydmVkIChuYcOvdmUpIFNJUg0KDQpgYGB7ciBib3VuZGFyaWVzLW1hcCwgZmlnLmFzcCA9ICg5LzE2KSwgZmlnLndpZHRoID0gMTUgKiAyLjV9DQoNCiMjIyBNYXAgb2JzZXJ2ZWQgU0lSIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCiMgRmluZCB0aGUgYWJzb2x1dGUgbWF4aW11bSBTSVIgb24gdGhlIGxvZyBzY2FsZQ0KDQptYXhfbG9nX3NpciA8LSBiYXNlOjphcy5pbnRlZ2VyKGJhc2U6Om1heChiYXNlOjphYnMoYmFzZTo6bG9nKGxpcF9zZltsaXBfc2Ykb2JzX2NhICE9IDAsIF0kb2JzX3Npcl9lc3QpKSkgLyAxKSArIDENCg0KIyBQcm9kdWNlIHRoZSByYXcgU0lSIG1hcCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KbWFwX29ic19zaXIgPC0gZ2dwbG90Mjo6Z2dwbG90KCkgKw0KICANCiAgIyBBZGQgZGlzdHJpY3RzIHdpdGggU0lSID4gMA0KICANCiAgZ2dwbG90Mjo6Z2VvbV9zZihkYXRhID0gbGlwX3NmICU+JSBkcGx5cjo6ZmlsdGVyKG9ic19zaXJfZXN0ID4gMCksDQogICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGdncGxvdDI6OmFlcyhmaWxsID0gb2JzX3Npcl9lc3QpLA0KICAgICAgICAgICAgICAgICAgIGNvbCA9ICJncmV5NTAiKSArDQogIA0KICAjIEFkZCBkaXN0cmljdHMgd2l0aCBTSVIgPSAwDQogIA0KICBnZ3Bsb3QyOjpnZW9tX3NmKGRhdGEgPSBsaXBfc2YgJT4lIGRwbHlyOjpmaWx0ZXIob2JzX3Npcl9lc3QgPT0gMCksDQogICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGdncGxvdDI6OmFlcyhhbHBoYSA9IGJhc2U6OmZhY3RvcigiU0lSID0gMCIsIG9yZGVyZWQgPSBUUlVFKSksDQogICAgICAgICAgICAgICAgICAgZmlsbCA9ICJncmV5OTAiLA0KICAgICAgICAgICAgICAgICAgIGNvbG91ciA9ICJncmV5NTAiLA0KICAgICAgICAgICAgICAgICAgIHNpemUgPSAwLjEpICsNCiAgDQogICMgQWRkIFNJUiBwcm9iYWJpbGl0eSBjYXRlZ29yeQ0KICANCiAgZ2dwbG90Mjo6Z2VvbV9wb2ludChkYXRhID0gbGlwX3NmICU+JSBkcGx5cjo6ZmlsdGVyKG9ic19zaXJfY2F0ICE9ICIiKSwNCiAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gZ2dwbG90Mjo6YWVzKHNoYXBlID0gb2JzX3Npcl9jYXQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tZXRyeSA9IGdlb20pLA0KICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgIHN0YXQgPSAic2ZfY29vcmRpbmF0ZXMiKSArDQogIA0KICAjIEFkZCBTY290bGFuZCBib3VuZGFyeQ0KICANCiAgZ2dwbG90Mjo6Z2VvbV9zZihkYXRhID0gc2N0X3NmLA0KICAgICAgICAgICAgICAgICAgIGZpbGwgPSBOQSwNCiAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSAiQmxhY2siLA0KICAgICAgICAgICAgICAgICAgIGxpbmV3aWR0aCA9IDEpICsNCiAgDQogICMgQWRkIGZpbGwgYWVzdGhldGljIGdyYWRpZW50IG1hcHBpbmcNCiAgDQogIGdncGxvdDI6OnNjYWxlX2ZpbGxfZ3JhZGllbnQyKCJPYnNlcnZlZCBTSVIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3cgPSBjb2xfcGFsWyJsb3ciXSwgIyBibHVlDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pZCA9IGNvbF9wYWxbIm1pZCJdLCAjIHllbGxvdw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoaWdoID0gY29sX3BhbFsiaGlnaCJdLCAjIGRhcmtibHVlDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pZHBvaW50ID0gMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEudmFsdWUgPSBOQSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYyhiYXNlOjpleHAoLW1heF9sb2dfc2lyKSwgYmFzZTo6ZXhwKG1heF9sb2dfc2lyKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGJhc2U6OmV4cChiYXNlOjpzZXEoLW1heF9sb2dfc2lyLCBtYXhfbG9nX3NpciwgMC41KSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGJhc2U6OmZvcm1hdChiYXNlOjpyb3VuZChleHAoc2VxKC1tYXhfbG9nX3NpciwgbWF4X2xvZ19zaXIsIDAuNSkpLCAyKSwgbnNtYWxsID0gMiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zID0gImxvZyIpICsNCiAgDQogIGdncGxvdDI6OnNjYWxlX2FscGhhX21hbnVhbCh2YWx1ZXMgPSBjKCJTSVIgPSAwIiA9IDEpKSArDQogIA0KICAjIEFkZCBzaGFwZSBhZXN0aGljIG1hcHBpbmcNCiAgDQogIGdncGxvdDI6OnNjYWxlX3NoYXBlX21hbnVhbCgiUHJvYmFiaWxpdHkgdmFsdWUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygiKysiID0gMjQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIrIiA9IDIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICItIiA9IDYsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICItLSIgPSAyNSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBjKCIrKyIsICIrIiwgIi0iLCAiLS0iKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIisrIiA9ICJTSVIgPiAxLCBwIDwgMC4wMSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIrIiA9ICJTSVIgPiAxLCBwIDwgMC4wNSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICItIiA9ICJTSVIgPCAxLCBwIDwgMC4wNSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICItLSIgPSAiU0lSIDwgMSwgcCA8IDAuMDEiKSkgKw0KICANCiAgIyBBZGQgY29kZSBsYWJlbHMgdG8gaWRlbnRpZnkgZGlzdHJpY3RzDQogIA0KICAjIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbChkYXRhID0gbGlwX3NmICU+JSBkcGx5cjo6ZmlsdGVyKCEgZGlzdF9uYW1lICVpbiUgZXhjX2xhYmVscyksDQogICMgICAgICAgICAgICAgICAgICAgICAgICAgIGluaGVyaXQuYWVzID0gRkFMU0UsDQogICMgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBnZ3Bsb3QyOjphZXMobGFiZWwgPSBkaXN0X25hbWUsDQogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbWV0cnkgPSBnZW9tKSwNCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdCA9ICJzZl9jb29yZGluYXRlcyIsDQogICMgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcmNlID0gMCwNCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAid2hpdGUiLA0KICAjICAgICAgICAgICAgICAgICAgICAgICAgICBiZy5jb2xvciA9ICJncmV5MzAiLA0KICAjICAgICAgICAgICAgICAgICAgICAgICAgICBiZy5yID0gMC4xLA0KICAjICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gOS8ucHQpICsNCiAgDQogICMgUHJldHR5IHVwIHRoZSBsZWdlbmQNCiAgDQogIGdncGxvdDI6Omd1aWRlcyhmaWxsID0gZ2dwbG90Mjo6Z3VpZGVfY29sb3VyYmFyKGZyYW1lLmNvbG91ciA9ICJibGFjayIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmcmFtZS5saW5ld2lkdGggPSAwLjI1LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aWNrcy5jb2xvdXIgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aWNrcy5saW5ld2lkdGggPSAwLjI1LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcmRlciA9IDEpLA0KICAgICAgICAgICAgICAgICAgYWxwaGEgPSBnZ3Bsb3QyOjpndWlkZV9sZWdlbmQodGl0bGUgPSBOVUxMLCBvcmRlciA9IDIpKSArDQogIA0KICAjIFByZXR0eSB1cCB0aGUgbWFwDQogIA0KICBnZ3Bsb3QyOjp0aGVtZV9idygpICsgDQogIA0KICBnZ3Bsb3QyOjp0aGVtZShheGlzLnRpdGxlID0gZ2dwbG90Mjo6ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICAgICBheGlzLnRleHQgPSBnZ3Bsb3QyOjplbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgICAgICAgIGF4aXMudGlja3MgPSBnZ3Bsb3QyOjplbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiaW5zaWRlIiwNCiAgICAgICAgICAgICAgICAgbGVnZW5kLm1hcmdpbiA9IGdncGxvdDI6Om1hcmdpbigtMywgMCwgMCwgMCksDQogICAgICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbi5pbnNpZGUgPSBjKDAuMTUsIDAuODUpLA0KICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgcGFuZWwuZ3JpZCA9IGdncGxvdDI6OmVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgIHRleHQgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoc2l6ZSA9IDEyKSkNCg0KIyBNYXAgcmVsYXRpdmUgc3RhbmRhcmQgZXJyb3JzIGZvciB0aGUgb2JzZXJ2ZWQgU0lSIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KbWFwX29ic19yc2UgPC0gZ2dwbG90Mjo6Z2dwbG90KGRhdGEgPSBsaXBfc2YpICsNCiAgDQogICMgQWRkIHJlbGF0aXZlIHN0YW5kYXJkIGVycm9ycyBmb3IgZGlzdHJpY3RzIHdpdGggU0lSID4gMA0KICANCiAgIyBBZGQgZGlzdHJpY3RzIHdpdGggU0lSID4gMA0KICANCiAgZ2dwbG90Mjo6Z2VvbV9zZihkYXRhID0gbGlwX3NmICU+JSBkcGx5cjo6ZmlsdGVyKG9ic19zaXJfZXN0ID4gMCksDQogICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGdncGxvdDI6OmFlcyhmaWxsID0gb2JzX3Npcl9yc2UpLA0KICAgICAgICAgICAgICAgICAgIGNvbCA9ICJncmV5NTAiKSArDQogIA0KICAjIEFkZCBkaXN0cmljdHMgd2l0aCBTSVIgPSAwDQogIA0KICBnZ3Bsb3QyOjpnZW9tX3NmKGRhdGEgPSBsaXBfc2YgJT4lIGRwbHlyOjpmaWx0ZXIob2JzX3Npcl9lc3QgPT0gMCksDQogICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGdncGxvdDI6OmFlcyhhbHBoYSA9IGJhc2U6OmZhY3RvcigiU0lSID0gMCIsIG9yZGVyZWQgPSBUUlVFKSksDQogICAgICAgICAgICAgICAgICAgZmlsbCA9ICJncmV5OTAiLA0KICAgICAgICAgICAgICAgICAgIGNvbG91ciA9ICJncmV5NTAiLA0KICAgICAgICAgICAgICAgICAgIHNpemUgPSAwLjEpICsNCiAgDQogICMgQWRkIFNjb3RsYW5kIGJvdW5kYXJ5DQogIA0KICBnZ3Bsb3QyOjpnZW9tX3NmKGRhdGEgPSBzY3Rfc2YsDQogICAgICAgICAgICAgICAgICAgZmlsbCA9IE5BLA0KICAgICAgICAgICAgICAgICAgIGNvbG91ciA9ICJCbGFjayIsDQogICAgICAgICAgICAgICAgICAgbGluZXdpZHRoID0gMSkgKw0KICANCiAgIyBBZGQgY29kZSBsYWJlbHMgdG8gaWRlbnRpZnkgZGlzdHJpY3RzDQogIA0KICBnZ3JlcGVsOjpnZW9tX3RleHRfcmVwZWwoZGF0YSA9IChsaXBfc2YgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHBseXI6OmZpbHRlcihkaXN0X25hbWUgJWluJSBjKCJCZXJ3aWNrc2hpcmUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSW52ZXJuZXNzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFiZXJkZWVuIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdsYXNnb3ciKSkpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5oZXJpdC5hZXMgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBnZ3Bsb3QyOjphZXMobGFiZWwgPSBkaXN0X25hbWUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21ldHJ5ID0gZ2VvbSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0ID0gInNmX2Nvb3JkaW5hdGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcmNlID0gMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gIndoaXRlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGJnLmNvbG9yID0gImdyZXkzMCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBiZy5yID0gMC4xLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDEyLy5wdCkgKw0KICANCiAgIyBBZGQgZmlsbCBhZXN0aGV0aWMgZ3JhZGllbnQgbWFwcGluZw0KICANCiAgZ2dwbG90Mjo6c2NhbGVfZmlsbF9ncmFkaWVudDIoIlJlbGF0aXZlIHN0YW5kYXJkIGVycm9yIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG93ID0gY29sX3BhbFsibG93Il0sICMgYmx1ZQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaWQgPSBjb2xfcGFsWyJtaWQiXSwgIyB5ZWxsb3cNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGlnaCA9IGNvbF9wYWxbImhpZ2giXSwgIyBkYXJrYmx1ZQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaWRwb2ludCA9IDAuNSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEudmFsdWUgPSBOQSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygwLCAxKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gYmFzZTo6c2VxKDAsIDEsIDAuMSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGJhc2U6OnNlcSgwLCAxLCAwLjEpKSArDQogIA0KICBnZ3Bsb3QyOjpzY2FsZV9hbHBoYV9tYW51YWwodmFsdWVzID0gYygiU0lSID0gMCIgPSAxKSkgKw0KICANCiAgZ2dwbG90Mjo6Z3VpZGVzKGZpbGwgPSBnZ3Bsb3QyOjpndWlkZV9jb2xvdXJiYXIoZnJhbWUuY29sb3VyID0gImJsYWNrIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZyYW1lLmxpbmV3aWR0aCA9IDAuMjUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpY2tzLmNvbG91ciA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpY2tzLmxpbmV3aWR0aCA9IDAuMjUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yZGVyID0gMSksDQogICAgICAgICAgICAgICAgICBhbHBoYSA9IGdncGxvdDI6Omd1aWRlX2xlZ2VuZCh0aXRsZSA9IE5VTEwsIG9yZGVyID0gMikpICsNCiAgDQogIGdncGxvdDI6OnRoZW1lX2J3KCkgKyANCiAgDQogIGdncGxvdDI6OnRoZW1lKGF4aXMudGl0bGUgPSBnZ3Bsb3QyOjplbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgICAgICAgIGF4aXMudGV4dCA9IGdncGxvdDI6OmVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICAgICAgICAgYXhpcy50aWNrcyA9IGdncGxvdDI6OmVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJpbnNpZGUiLA0KICAgICAgICAgICAgICAgICBsZWdlbmQubWFyZ2luID0gZ2dwbG90Mjo6bWFyZ2luKC0zLCAwLCAwLCAwKSwNCiAgICAgICAgICAgICAgICAgIyBsZWdlbmQucG9zaXRpb24uaW5zaWRlID0gYygwLjE1LCAwLjg4KSwNCiAgICAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uLmluc2lkZSA9IGMoMC4xOCwgMC45MCksDQogICAgICAgICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KHNpemUgPSAxMCksDQogICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICBwYW5lbC5ncmlkID0gZ2dwbG90Mjo6ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgdGV4dCA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChzaXplID0gMTIpKQ0KDQojIE1hcCBleHBlY3RlZCBwcmVjaXNpb24gb2YgU0lSIHByb3BvcnRpb25hbCB0byBleHBlY3RlZCBjYW5jZXIgY2FzZXMgLS0tLS0tLS0tLS0NCg0KbWFwX2V4cF9yc2UgPC0gZ2dwbG90Mjo6Z2dwbG90KGRhdGEgPSBsaXBfc2YpICsNCiAgDQogICMgQWRkIHJlbGF0aXZlIHN0YW5kYXJkIGVycm9ycyBmb3IgZGlzdHJpY3RzIHdpdGggU0lSID4gMA0KICANCiAgIyBBZGQgZGlzdHJpY3RzIHdpdGggRShSKSA+IDANCiAgDQogIGdncGxvdDI6Omdlb21fc2YoZGF0YSA9IGxpcF9zZiwgIyAgJT4lIGRwbHlyOjpmaWx0ZXIob2JzX3Npcl9lc3QgPiAwKSwNCiAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gZ2dwbG90Mjo6YWVzKGZpbGwgPSBleHBfc2lyX3JzZSksDQogICAgICAgICAgICAgICAgICAgY29sID0gImdyZXk1MCIpICsNCiAgDQogICMgQWRkIFNjb3RsYW5kIGJvdW5kYXJ5DQogIA0KICBnZ3Bsb3QyOjpnZW9tX3NmKGRhdGEgPSBzY3Rfc2YsDQogICAgICAgICAgICAgICAgICAgZmlsbCA9IE5BLA0KICAgICAgICAgICAgICAgICAgIGNvbG91ciA9ICJCbGFjayIsDQogICAgICAgICAgICAgICAgICAgbGluZXdpZHRoID0gMSkgKw0KICANCiAgIyBBZGQgZmlsbCBhZXN0aGV0aWMgZ3JhZGllbnQgbWFwcGluZw0KDQogIGdncGxvdDI6OnNjYWxlX2ZpbGxfZ3JhZGllbnQyKGJhc2U6OmV4cHJlc3Npb24oIlNFKFIpIiAlcHJvcCUgIjEvRSIpLCAjICJFeHBlY3RlZCBwcmVjaXNpb24gb2YgU0lSIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG93ID0gY29sX3BhbFsibG93Il0sICMgYmx1ZQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaWQgPSBjb2xfcGFsWyJtaWQiXSwgIyB5ZWxsb3cNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGlnaCA9IGNvbF9wYWxbImhpZ2giXSwgIyBkYXJrYmx1ZQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaWRwb2ludCA9IDAuNSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEudmFsdWUgPSBOQSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygwLCAxKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gYmFzZTo6c2VxKDAsIDEsIDAuMSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGJhc2U6OnNlcSgwLCAxLCAwLjEpKSArDQogIA0KICAjIGdncGxvdDI6OnNjYWxlX2FscGhhX21hbnVhbCh2YWx1ZXMgPSBjKCJTSVIgPSAwIiA9IDEpKSArDQogIA0KICBnZ3Bsb3QyOjpndWlkZXMoZmlsbCA9IGdncGxvdDI6Omd1aWRlX2NvbG91cmJhcihmcmFtZS5jb2xvdXIgPSAiYmxhY2siLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnJhbWUubGluZXdpZHRoID0gMC4yNSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGlja3MuY29sb3VyID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGlja3MubGluZXdpZHRoID0gMC4yNSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JkZXIgPSAxKSwNCiAgICAgICAgICAgICAgICAgIGFscGhhID0gZ2dwbG90Mjo6Z3VpZGVfbGVnZW5kKHRpdGxlID0gTlVMTCwgb3JkZXIgPSAyKSkgKw0KICANCiAgZ2dwbG90Mjo6dGhlbWVfYncoKSArIA0KICANCiAgZ2dwbG90Mjo6dGhlbWUoYXhpcy50aXRsZSA9IGdncGxvdDI6OmVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICAgICAgICAgYXhpcy50ZXh0ID0gZ2dwbG90Mjo6ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICAgICBheGlzLnRpY2tzID0gZ2dwbG90Mjo6ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImluc2lkZSIsDQogICAgICAgICAgICAgICAgIGxlZ2VuZC5tYXJnaW4gPSBnZ3Bsb3QyOjptYXJnaW4oLTMsIDAsIDAsIDApLA0KICAgICAgICAgICAgICAgICAjIGxlZ2VuZC5wb3NpdGlvbi5pbnNpZGUgPSBjKDAuMTUsIDAuODgpLA0KICAgICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24uaW5zaWRlID0gYygwLjEzLCAwLjkwNSksDQogICAgICAgICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KHNpemUgPSAxMCksDQogICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICBwYW5lbC5ncmlkID0gZ2dwbG90Mjo6ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgdGV4dCA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChzaXplID0gMTIpKQ0KDQojIyBPdXRwdXQgb2JzZXJ2ZWQgYW5kIEJZTSBzbW9vdGhlZCBTSVIgZm9yIGxpcCBjYW5jZXIgcmlzayAtLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQoobWFwX29ic19zaXIgfCBtYXBfb2JzX3JzZSB8IG1hcF9leHBfcnNlKSArDQogIHBhdGNod29yazo6cGxvdF9hbm5vdGF0aW9uKHRpdGxlID0gIk9ic2VydmVkIFNJUiBlc3RpbWF0ZXMgYW5kIHAtdmFsdWVzIGFuZCBvYnNlcnZlZCBhbmQgZXhwZWN0ZWQgcmVsYXRpdmUgc3RhbmRhcmQgZXJyb3JzIGZvciBtYWxlIGxpcCBjYW5jZXIgaW4gU2NvdGxhbmQgKDE5NzUtMTk4MCkiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUgPSB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkpDQoNCmBgYA0KDQojIyMgUXVlZW4gYWRqYWNlbmN5IG1hdHJpeA0KDQpQcmlvciB0byBjb25kdWN0aW5nIHRoZSBCWU0gQ0FSIGFuYWx5c2lzLCB3ZSBuZWVkIHRvIGNvbnN0cnVjdCB0aGUgcXVlZW4gYWRqYWNlbmN5IG1hdHJpeC4gVGhpcyBpcyBlYXNpbHkgdXNpbmcgdGhlIGBzcGRlcDo6cG9seTJuYmAgZnVuY3Rpb24uDQoNCmBgYHtyIGFkamFjZW5jeS1tYXRyaXh9DQoNCiMjIyBDcmVhdGUgUXVlZW4gYWRqYWNlbmN5IChjb250aWd1aXR5KSBsaXN0IGZvciBlYWNoIGRpc3RyaWN0IC0tLS0tLS0tLS0tLS0tLS0tDQoNCiMgVGhlIHNwZGVwOjpwb2x5Mm5iIGZ1bmN0aW9uIGNvbnN0cnVjdHMgYSBsaXN0IG9mIG5laWdoYm91cnMgZnJvbSBhIHBvbHlnb24gb2JqZWN0DQoNCmFkal9uYl9saXN0IDwtIHNwZGVwOjpwb2x5Mm5iKGxpcF9zZiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBxdWVlbiA9IFRSVUUsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93Lm5hbWVzID0gYmFzZTo6cm93Lm5hbWVzKGxpcF9zZikpDQoNCmJhc2U6OnByaW50KGFkal9uYl9saXN0KQ0KICANCiMgVmlldyBhZGphY2VuY3kgbGlzdCBzdHJ1Y3R1cmUNCg0KdXRpbHM6OmhlYWQoYWRqX25iX2xpc3QpDQoNCmBgYA0KDQpUaGUgd2FybmluZyBtZXNzYWdlIGlzIHRlbGxpbmcgdXMgdGhyZWUgZGlzdHJpY3RzIChkaXN0cmljdHMgNiwgOCBhbmQgMTEpIGhhdmUgbm8gbmVpZ2hib3Vycywgd2hpY2ggaXMgcmVhc29uYWJsZSBhcyB0aGVyZSBhcmUgdGhyZWUgaXNsYW5kIGFyZWFzIChkaXN0cmljdHMpLCBhbmQgdGhhdCBvbmUgaGFzIChkaXN0cmljdCA0KSBoYXMgZGlzam9pbnQgY29ubmVjdGVkIHN1YmdyYXBocy4gVGhpcyBsaWtlbHkgbWVhbnMgdGhlIGFyZWEgaXMgc2hhcmluZyBtdWx0aXBsZSBib3JkZXJzIChlZGdlcykgd2l0aCB0aGUgc2FtZSBuZWlnaGJvdXIuIFRoaXMgY2FuIG9jY3VyIHdoZW4gdGhlcmUgYSAic2xpdmVycyIgLS0tIHNtYWxsIGdhcHMgLS0tIGluIHlvdXIgc3BhdGlhbCBkYXRhIGJldHdlZW4gYm9yZGVyaW5nIHNwYXRpYWwgdW5pdHMuIEdpdmVuIHRoZSBtYXAgYXZhaWxhYmxlIGZvciBTY290bGFuZCBsb29rcyBsaWtlIGEgZml2ZS15ZWFyIG9sZCBoYXMgY3V0IGl0IG91dCBvZiBjb2xvdXJlZCBwYXBlciB3aXRoIGJsdW50IGNyYWZ0IHNjaXNzb3JzIGFuZCBmcm9tIG1lbW9yeSwgdGhpcyBhbG1vc3QgY2VydGFpbmx5IGxpa2VseS4gV2UgY2FuIGNoZWNrIHRoZXNlIHdhcm5pbmdzIGFyZSBPSyB2aWEgc29tZSBhZGRpdGlvbmFsIG1hcHMuDQoNCmBgYHtyIGRpc3QtY29kZXMsIGZpZy5hc3AgPSAoOS8xNiksIGZpZy53aWR0aCA9IDE1ICogMi41fQ0KDQojIFByb3ZpZGUgZGlzdHJpY3QgbWFwIGZvciByZWZlcmVuY2UgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQphZGpfZGlzdF9tYXAgPC0gZ2dwbG90Mjo6Z2dwbG90KCkgKw0KICANCiAgIyBBZGQgZGlzdHJpY3RzIHdpdGggU0lSID4gMA0KICANCiAgZ2dwbG90Mjo6Z2VvbV9zZihkYXRhID0gbGlwX3NmLA0KICAgICAgICAgICAgICAgICAgIGZpbGwgPSBOQSwNCiAgICAgICAgICAgICAgICAgICBjb2wgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgIGxpbmV3aWR0aCA9IDAuMjUpICsNCiAgDQogICMgQWRkIFNjb3RsYW5kIGJvdW5kYXJ5DQogIA0KICBnZ3Bsb3QyOjpnZW9tX3NmKGRhdGEgPSBzY3Rfc2YsDQogICAgICAgICAgICAgICAgICAgZmlsbCA9IE5BLA0KICAgICAgICAgICAgICAgICAgIGNvbG91ciA9ICJCbGFjayIsDQogICAgICAgICAgICAgICAgICAgbGluZXdpZHRoID0gMSkgKw0KICANCiAgIyBBZGQgY29kZSBsYWJlbHMgdG8gaWRlbnRpZnkgZGlzdHJpY3RzDQogIA0KICBnZ3Bsb3QyOjpnZW9tX3RleHQoZGF0YSA9IGxpcF9zZiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGluaGVyaXQuYWVzID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gZ2dwbG90Mjo6YWVzKGxhYmVsID0gZGlzdF9jb2RlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tZXRyeSA9IGdlb20pLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdCA9ICJzZl9jb29yZGluYXRlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMTIvLnB0KSArDQogIA0KICBnZ3Bsb3QyOjp0aGVtZV9idygpICsgDQogIA0KICBnZ3Bsb3QyOjp0aGVtZShheGlzLnRpdGxlID0gZ2dwbG90Mjo6ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICAgICBheGlzLnRleHQgPSBnZ3Bsb3QyOjplbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgICAgICAgIGF4aXMudGlja3MgPSBnZ3Bsb3QyOjplbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiaW5zaWRlIiwNCiAgICAgICAgICAgICAgICAgbGVnZW5kLm1hcmdpbiA9IGdncGxvdDI6Om1hcmdpbigtMywgMCwgMCwgMCksDQogICAgICAgICAgICAgICAgICMgbGVnZW5kLnBvc2l0aW9uLmluc2lkZSA9IGMoMC4xNSwgMC44OCksDQogICAgICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbi5pbnNpZGUgPSBjKDAuMTMsIDAuOTA1KSwNCiAgICAgICAgICAgICAgICAgbGVnZW5kLnRleHQgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwNCiAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgIHBhbmVsLmdyaWQgPSBnZ3Bsb3QyOjplbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICB0ZXh0ID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KHNpemUgPSAxMikpDQoNCiMgTWFwIHNvbWUgbmVpZ2hib3VycyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCmFkal9uYl9tYXAgPC0gZ2dwbG90Mjo6Z2dwbG90KCkgKw0KICANCiAgDQogICMgQWRkIGRpc3RyaWN0cw0KICANCiAgZ2dwbG90Mjo6Z2VvbV9zZihkYXRhID0gbGlwX3NmLA0KICAgICAgICAgICAgICAgICAgIGNvbG91ciA9ICJncmV5NTAiLA0KICAgICAgICAgICAgICAgICAgIGZpbGwgPSBOQSwNCiAgICAgICAgICAgICAgICAgICBsaW5ld2lkdGggPSAwLjEpICsNCiAgDQogICMgQXJlYXMgb2YgaW50ZXJlc3QNCiAgDQogICMgIDQgPSBCZXJ3aWNrc2hpcmUNCiAgIyAxOSA9IEludmVybmVzcw0KICAjIDIyID0gQWJlcmRlZW4NCiAgIyA0OSA9IEdsYXNnb3cNCiAgDQogIGdncGxvdDI6Omdlb21fc2YoZGF0YSA9IGxpcF9zZiAlPiUgZmlsdGVyKHJvdy5uYW1lcyguKSAlaW4lIGMoNCwgMTksIDIyLCA0OSkpLA0KICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBnZ3Bsb3QyOjphZXMoZmlsbCA9ICJBbmFseXNpcyBkaXN0cmljdCIpLA0KICAgICAgICAgICAgICAgICAgIGNvbG91ciA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgbGluZXdpZHRoID0gMC4xKSArDQogIA0KICAjIE5laWdoYm91cnMgb2YgYXJlYXMgb2YgaW50ZXJlc3QNCiAgDQogIGdncGxvdDI6Omdlb21fc2YoZGF0YSA9IGxpcF9zZiAlPiUgZmlsdGVyKHJvdy5uYW1lcyguKSAlaW4lIHVubGlzdChhZGpfbmJfbGlzdFtjKDQsIDE5LCAyMiwgNDkpXSkpLA0KICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoZmlsbCA9ICJRdWVlbiBuZWlnaGJvdXJzIiksDQogICAgICAgICAgICAgICAgICAgY29sb3VyID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgICBsaW5ld2lkdGggPSAwLjEpICsNCiAgDQogICMgQWRkIFNjb3RsYW5kIGJvdW5kYXJ5DQogIA0KICBnZ3Bsb3QyOjpnZW9tX3NmKGRhdGEgPSBzY3Rfc2YsDQogICAgICAgICAgICAgICAgICAgZmlsbCA9IE5BLA0KICAgICAgICAgICAgICAgICAgIGNvbG91ciA9ICJCbGFjayIsDQogICAgICAgICAgICAgICAgICAgbGluZXdpZHRoID0gMSkgKw0KICANCiAgIyBBZGQgY29kZSBsYWJlbHMgdG8gaWRlbnRpZnkgZGlzdHJpY3RzDQogIA0KICBnZ3JlcGVsOjpnZW9tX3RleHRfcmVwZWwoZGF0YSA9IChsaXBfc2YgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHBseXI6OmZpbHRlcihkaXN0X25hbWUgJWluJSBjKCJCZXJ3aWNrc2hpcmUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSW52ZXJuZXNzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFiZXJkZWVuIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdsYXNnb3ciKSkpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5oZXJpdC5hZXMgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBnZ3Bsb3QyOjphZXMobGFiZWwgPSBkaXN0X25hbWUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21ldHJ5ID0gZ2VvbSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0ID0gInNmX2Nvb3JkaW5hdGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcmNlID0gMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gIndoaXRlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGJnLmNvbG9yID0gImdyZXkzMCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBiZy5yID0gMC4xLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDEyLy5wdCkgKw0KICANCiAgIyBBZGQgZmlsbCBhZXN0aGV0aWMgZ3JhZGllbnQgbWFwcGluZw0KICANCiAgZ2dwbG90Mjo6c2NhbGVfZmlsbF9tYW51YWwoIkFkamFjZW5jeSBleGFtcGxlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGMoIkFuYWx5c2lzIGRpc3RyaWN0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUXVlZW4gbmVpZ2hib3VycyIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKHJnYigyMzAsIDcwLCAzOCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmdiKDI1NSwgMjEyLCAxMDIsIG1heENvbG9yVmFsdWUgPSAyNTUpKSkgKw0KICANCiAgIyBBZGQgWCBhbmQgWSBjb29yZGluYXRlIGxhYmVscw0KICANCiAgZ2dwbG90Mjo6dGhlbWVfYncoKSArDQogIA0KICBnZ3Bsb3QyOjp0aGVtZShheGlzLnRpdGxlID0gZ2dwbG90Mjo6ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICAgICBheGlzLnRleHQgPSBnZ3Bsb3QyOjplbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgICAgICAgIGF4aXMudGlja3MgPSBnZ3Bsb3QyOjplbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiaW5zaWRlIiwNCiAgICAgICAgICAgICAgICAgbGVnZW5kLm1hcmdpbiA9IGdncGxvdDI6Om1hcmdpbigwLCAwLCAwLCAwKSwNCiAgICAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uLmluc2lkZSA9IGMoMC4yLCAwLjkzKSwNCiAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgIHBhbmVsLmdyaWQgPSBnZ3Bsb3QyOjplbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICB0ZXh0ID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KHNpemUgPSAxMikpDQoNCiMgUGxvdCBuZWlnaGJvdXJzIGNvbm5lY3Rpdml0eSBncmFwaCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCiMgR2VuZXJlYXRlIGNvbm5lY3Rpdml0eSBhcmNzIGJldHdlZW4gc3BhdGlhbCB1bml0cyBhbmQgdGhlaXIgbmVpZ2hib3Vycw0KDQojIEZyb206IGh0dHBzOi8vbWJqb3NlcGguZ2l0aHViLmlvL3Bvc3RzLzIwMTgtMTItMjctcGxvdHRpbmctc3BhdGlhbC1uZWlnaGJvcnMtaW4tZ2dwbG90Mi8NCg0KIyBUaGUgc3BkZXA6Om5iMmxpbmVzIGZ1bmN0aW9uIGNyZWF0ZXMgbGluZXN0cmluZyBnZW9tZXRyaWVzIGxpbmtpbmcgdGhlIGNlbnRyb2lkcw0KIyBvZiBuZWlnaGJvdXJpbmcgZGlzdHJpY3RzDQoNCmFkal9uYl9hcmMgPC0gc3BkZXA6Om5iMmxpbmVzKGFkal9uYl9saXN0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29vcmRzID0gc3RfY2VudHJvaWQoc3RfZ2VvbWV0cnkobGlwX3NmKSkpDQoNCiMgQ2FsY3VsYXRlIHRoZSBudW1iZXIgb2YgbmVpZ2hib3VycyBmb3IgZWFjaCBkaXN0cmljdCBieSBzdW1tYXJpc2luZyB0aGUgbGVuZ3RoDQojIG9mIGVhY2ggZWxlbWVudCBpbiB0aGUgYWRqX25iX2xpc3QNCg0KYWRqX25iX251bSA8LSBsYXBwbHkoYWRqX25iX2xpc3QsIGxlbmd0aCkgJT4lDQogIGRvLmNhbGwocmJpbmQsIC4pICU+JQ0KICBhcy5kYXRhLmZyYW1lKCkgJT4lDQogIHNldE5hbWVzKCJuZWlnaGJvdXJzIikNCg0KIyMgTWFwIGFkamFjZW5jeSBtYXJrcyBhbmQgc3ltYm9saXNlIGJ5IG51bWJlciBvZiBuZWlnaGJvdXJzIC0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KYWRqX2Nvbl9tYXAgPC0gZ2dwbG90KCkgKw0KICANCiAgIyBBZGQgZGlzdHJpY3RzDQogIA0KICBnZW9tX3NmKGRhdGEgPSBsaXBfc2YgJT4lIGJpbmRfY29scyhhZGpfbmJfbnVtKSwNCiAgICAgICAgICBhZXMoZmlsbCA9IG5laWdoYm91cnMpLA0KICAgICAgICAgIGNvbG91ciA9ICJncmV5NTAiLA0KICAgICAgICAgIGxpbmV3aWR0aCA9IDAuMSwNCiAgICAgICAgICBhbHBoYSA9IDAuNzUpICsNCiAgDQogICMgQWRkIG5laWdoYm91ciBjb25uZWN0aXZpdHkgYXJjcw0KICANCiAgZ2VvbV9zZihkYXRhID0gYWRqX25iX2FyYywNCiAgICAgICAgICBjb2xvdXIgPSAiYmxhY2siLA0KICAgICAgICAgIGxpbmV3aWR0aCA9IDAuMSkgKw0KICANCiAgIyBBZGQgZGlzdHJpY3QgY2VudHJvaWRzDQogIA0KICBnZW9tX3NmKGRhdGEgPSBzdF9jZW50cm9pZChzdF9nZW9tZXRyeShsaXBfc2YpKSwNCiAgICAgICAgICBzaGFwZSA9IDE2LA0KICAgICAgICAgIGNvbG91ciA9ICJibGFjayIsDQogICAgICAgICAgc2l6ZSA9IDIuNzUpICsNCiAgDQogICMgQWRkIGNvZGUgbGFiZWxzIHRvIGlkZW50aWZ5IGRpc3RyaWN0cw0KICANCiAgZ2dyZXBlbDo6Z2VvbV90ZXh0X3JlcGVsKGRhdGEgPSBsaXBfc2YgJT4lIGRwbHlyOjpmaWx0ZXIoISBkaXN0X25hbWUgJWluJSBleGNfbGFiZWxzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGluaGVyaXQuYWVzID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gZ2dwbG90Mjo6YWVzKGxhYmVsID0gZGlzdF9uYW1lLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tZXRyeSA9IGdlb20pLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdCA9ICJzZl9jb29yZGluYXRlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBmb3JjZSA9IDAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJ3aGl0ZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBiZy5jb2xvciA9ICJncmV5MzAiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgYmcuciA9IDAuMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAxMi8ucHQpICsNCiAgDQogICMgQWRkIGZpbGwgYWVzdGhldGljIGdyYWRpZW50IG1hcHBpbmcNCiAgDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnQoIk5laWdoYm91cnMiLA0KICAgICAgICAgICAgICAgICAgICAgIGxvdyA9ICJsaWdodHllbGxvdyIsDQogICAgICAgICAgICAgICAgICAgICAgaGlnaCA9ICJkYXJrcmVkIiwNCiAgICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDAsIDExKSwNCiAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoMCwgMTEsIDEpLA0KICAgICAgICAgICAgICAgICAgICAgICMgbGFiZWxzID0gYygiMSIsICIiLCAiIiwgIiIsICIiLCAiNiIsICIiLCAiIiwgIiIsICIiLCAiIiwgIjEyIiksDQogICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9jb2xvcmJhcihmcmFtZS5jb2xvdXIgPSAiYmxhY2siLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZyYW1lLmxpbmV3aWR0aCA9IDAuMjUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aWNrcy5jb2xvdXIgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGlja3MubGluZXdpZHRoID0gMC4yNSkpICsNCiAgDQogIHRoZW1lX2J3KCkgKw0KICANCiAgdGhlbWUoYXhpcy50aXRsZSA9IGdncGxvdDI6OmVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50ZXh0ID0gZ2dwbG90Mjo6ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpY2tzID0gZ2dwbG90Mjo6ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICANCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImluc2lkZSIsDQogICAgICAgIGxlZ2VuZC5tYXJnaW4gPSBnZ3Bsb3QyOjptYXJnaW4oMCwgMCwgMCwgMCksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbi5pbnNpZGUgPSBjKDAuMTUsIDAuOTApLA0KICAgICAgICANCiAgICAgICAgcGFuZWwuZ3JpZCA9IGdncGxvdDI6OmVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgDQogICAgICAgIHRleHQgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoc2l6ZSA9IDEyKSkNCg0KIyMgT3V0cHV0IGFkamFjZW5jeSBtYXBzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KKGFkal9kaXN0X21hcCB8IGFkal9uYl9tYXAgfCBhZGpfY29uX21hcCkgKw0KICBwYXRjaHdvcms6OnBsb3RfYW5ub3RhdGlvbih0aXRsZSA9ICJTcGF0aWFsIG5laWdoYm91cnMgYW5kIGxpbmtzIG1hcHMgZm9yIFNjb3R0aXNoIGFkbWluaXN0cmF0aXZlIGRpc3RyaWN0cyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZSA9IHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSkNCg0KYGBgDQoNCkJhc2VkIG9uIHRoZXNlIG1hcHMsIHdlIGNhbiBiZSBjb25maWRlbnQgdGhlIHRocmVlIGRpc3RyaWN0cyB3aXRob3V0IG5laWdoYm91cnMgYXJlIGlzbGFuZCBhcmVhcyAoV2VzdGVybiBJc2xlcywgT3JrbmV5IGFuZCBTaGV0bGFuZCkgYW5kIHRoYXQgZGlzdHJpY3QgNCAoQmVyd2lja3NoaXJlKSBpcyBjb25uZWN0ZWQgdG8gdGhlIGNvcnJlY3QgbnVtYmVyIG9mIG5laWdoYm91cnMgKG49MykuIFdlIGNhbiBub3cgY29udmVydCB0aGUgYHNwZGVwYCBhZGphY2VuY3kgbWF0cml4IHRvIFdpbkJVR1Mgd2VpZ2h0IG1hdHJpeCBmb3JtYXQsIHdoaWNoIGlzIHJlcXVpcmVkIGZvciBmaXR0aW5nIEJZTSBDQVIgbW9kZWxzIGluIGBuaW1ibGVgLg0KDQpgYGB7ciB3Yi1tYXRyaXh9DQoNCiMjIyBPdXRwdXQgYWRqYWNlbmN5IG1hdHJpeCBpbiBXaW5CVUdTIGZvcm1hdCBmb3IgdXNlIGluIEJZTSBtb2RlbHMgLS0tLS0tLS0tLS0tDQoNCiMgVGhlIHNwZGVwOjpuYjJXQiBmdW5jdGlvbiBjYW4gYmUgdXNlZCB0byBtYWtlIFdpbkJVR1MgbmVpZ2hib3VycyBsaXN0IA0KDQphZGpfbmJfd2d0IDwtIHNwZGVwOjpuYjJXQihuYiA9IGFkal9uYl9saXN0KQ0KDQojIFZpZXcgV2luQlVJR1MgYWRqYWNlbmN5IGxpc3QNCg0KYmFzZTo6cHJpbnQoYWRqX25iX3dndCkNCg0KIyBUaGUgKmFkaiogdmVjdG9yIGRlZmluZXMgdGhlIGRpc3RyaWN0IGluZGV4ZXMgZm9yIHRoZSBuZWlnaGJvdXJzIG9mIHRoZSBpdGgNCiMgYW5hbHlzaXMgdW5pdDsgdGhlICp3ZWlnaHRzKiB2ZWN0b3IgaW5kaWNhdGVzIHRoZSB3ZWlnaHQgYXNzaWduZWQgdG8gZWFjaA0KIyBuZWlnaGJvdXIgd2hlbiBjYWxjdWxhdGluZyB0aGUgY29uZGl0aW9uYWwgYXV0b3JlZ3Jlc3Npb24gc3BhdGlhbCB0ZXJtDQojIGluIHRoZSBCWU0gbW9kZWw7IGFuZCAqbnVtKiBpbmRpY2F0ZXMgaG93IG1hbnkgb2YgdGhlIG5laWdoYm91cnMgaW4gKmFkaioNCiMgYm9yZGVyIHRoZSBpdGggYW5hbHlzaXMgdW5pdC4gRm9yIGV4YW1wbGUsIHRoZSBmaXJzdCBlbGVtZW50IG9mICpudW0qIGluZGljYXRlcw0KIyB0aGF0IHRoZSBkaXN0cmljdCBvZiBTa3llLUxvY2hhbHNoIChyb3cgMSBpbiAqbGlwX3NmKikgaGFzIHRocmVlIG5laWdoYm91cnMsIA0KIyB3aGljaCAqYWRqKiBpbmRpY2F0ZXMgY29ycmVzcG9uZCB0byByb3cgaW5kZXhlcyA1LCA5IGFuZCAxOSAoUm9zcy1Dcm9tYXJ0eSwNCiMgTG9jaGFiZXIgYW5kIEludmVybmVzcyBkaXN0cmljdHMpIGluICpsaXBfc2YqLCBhbmQgYXJlIGFzc2lnbmVkIHdlaWdodHMgb2YgMSwgDQojIDEgYW5kIDEgd2hlbiBjYWxjdWxhdGluZyB0aGUgQ0FSIHNwYXRpYWwgdGVybSBmb3IgU2t5ZS1Mb2NoYWxzaC4NCg0KYGBgDQoNCiMjIyBCWU0gQ0FSIGRpc2Vhc2UgbWFwcGluZyBtb2RlbA0KDQpXZSBub3cgaGF2ZSBldmVyeXRoaW5nIG5lY2Vzc2FyeSB0byBydW4gYSBCWU0gQ0FSIGRpc2Vhc2UgbWFwcGluZyBtb2RlbC4gQWxsIHRoYXQgaXMgbGVmdCBpcyB0byBmb3JtYXQgdGhlIGRhdGEgaW4gdGhlIHdheSBgbmltYmxlYCBleHBlY3RzIGl0IHRvIGJlLCB3cml0ZSBhbmQgY29tcGlsZSBvdXIgbW9kZWwsIGFuZCB0aGVuIHJ1biBhbmQgc3VtbWFyaXNlIGl0cyBvdXRwdXQuDQoNCmBgYHtyIEJZTSwgZmlnLmFzcCA9ICg5LzE2KSwgZmlnLndpZHRoID0gMTUgKiAyLjV9DQoNCiMjIyBBc3NlbWJsZSBvYmplY3RzIG5lZWRlZCB0byBydW4gYSBCWU0gZGlzZWFzZSBtb2RlbCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCiMjIE9idGFpbiB0aGUgbnVtYmVyIG9mIGRpc3RyaWN0cyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCk4gPC0gZGltKGxpcF9zZilbMV0NCg0KIyMgRm9ybWF0IFNJUiBkYXRhIGZvciBOSU1CTEUgaW4gYSBsaXN0IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KYnltX2RhdGEgPC0gYmFzZTo6bGlzdChvYnMgPSBsaXBfc2Ykb2JzX2NhKSAgICAgICAgICAgICAgICMgT2JzZXJ2ZWQgbGlwIGNhbmNlciBjYXNlcw0KDQojIyBMaXN0IGNvbnN0YW50cyByZXF1aXJlZCBieSBOSU1CTEUgdG8gZml0IEJZTSBtb2RlbCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQpieW1fY29uc3RzIDwtYmFzZTo6bGlzdChOID0gTiwgICAgICAgICAgICAgICAgICAgICAgICAgICMgTnVtYmVyIG9mIGRpc3RyaWN0cyANCiAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgZXhwID0gbGlwX3NmJGV4cF9jYSwgICAgICAgICAgICAgICAjIEV4cGVjdGVkIGxpcCBjYW5jZXIgY2FzZXMNCiAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgIyBBZGphY2VuY3kgbWF0cml4IHZhbHVlcyB1c2VkIHRvIHNwZWNpZnkgQ0FSIGRpc3RyaWJ1dGlvbg0KICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICBMID0gbGVuZ3RoKGFkal9uYl93Z3Qkd2VpZ2h0cyksICAjIFRvdGFsIG51bWJlciBvZiBuZWlnaGJvdXJzICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgIGFkaiA9IGFkal9uYl93Z3QkYWRqLCAgICAgICAgICAgICMgVmVjdG9yIG9mIG5laWdoYm91cnMgZm9yIGVhY2ggZGl0cmljdCAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgIG51bSA9IGFkal9uYl93Z3QkbnVtLCAgICAgICAgICAgICMgVmVjdG9yIG9mIG5laWdoYm91ciBjb3VudHMgZm9yIGVhY2ggZGlzdHJpY3QNCiAgICAgICAgICAgICAgICAgICAgICAgIHdlaWdodHMgPSBhZGpfbmJfd2d0JHdlaWdodHMpICAgICMgV2VpZ2h0IGZvciBlYWNoIG5laWdoYm91ciAoYWxsIDEgZm9yIGEgcXVlZW4gbWF0cml4DQoNCmJhc2U6OnByaW50KGJ5bV9jb25zdHMpDQoNCiMjIFdyaXRlIHRoZSBtb2RlbCBzcGVjaWZpY2F0aW9uIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCiMgTk9URTogRG9uJ3QgdXNlIFIgbmFtZXNwYWNlcyBhcyBtb2RlbHMgYXJlIHJ1biBieSB0aGUgbmltYmxlIEMrKyBjb21waWxlcg0KDQpieW1fY29kZSA8LSBuaW1ibGU6Om5pbWJsZUNvZGUoDQogIHsNCiAgICBmb3IgKGkgaW4gMTpOKXsNCiAgICAgIA0KICAgICAgIyBQb2lzc29uIGxpa2VsaWhvb2QgZm9yIG9ic2VydmVkIGNvdW50cw0KICAgICAgDQogICAgICBvYnNbaV0gfiBkcG9pcyhsYW1iZGFbaV0pIA0KICAgICAgbG9nKGxhbWJkYVtpXSkgPC0gYWxwaGEgKyBzW2ldICsgdVtpXSArIGxvZyhleHBbaV0pDQogICAgICANCiAgICAgICMgUHJpb3IgZm9yIHRoZSBhcmVhLXNwZWNpZmljIHVuc3RydWN0dXJlZCByYW5kb20gZWZmZWN0DQogICAgICANCiAgICAgIHVbaV0gfiBkbm9ybSgwLCB0YXUgPSB0YXUudSkgICAgDQogICAgICANCiAgICAgICMgU21vb3RoZWQgYXJlYS1zcGVjaWZpYyBTSVINCiAgICAgIA0KICAgICAgc21vb3RoZWQuc2lyW2ldIDwtIGV4cChhbHBoYSArIHNbaV0gKyB1W2ldKQ0KICAgICAgDQogICAgICAjIE92ZXJhbGwgcmVzaWR1YWwgYXJlYS1zcGVjaWZpYyBjYW5jZXIgcmlzayBhYm92ZSBvciBiZWxvdyB0aGUgU2NvdHRpc2ggYXZlcmFnZQ0KICAgICAgDQogICAgICByZXNpZHVhbC5zaXJbaV0gPC0gZXhwKHNbaV0gKyB1W2ldKQ0KICAgICAgDQogICAgICAjIFJlc2lkdWFsIGFyZWEtc3BlY2lmaWMgY2FuY2VyIHJpc2sgZHVlIHRvIHVub2JzZXJ2ZWQgYW5kIHNwYXRpYWxseSBzdHJ1Y3R1cmVkIGZhY3RvcnMgKHMpDQogICAgICANCiAgICAgIHJlc2lkdWFsLnNpci5zW2ldIDwtIGV4cChzW2ldKQ0KICAgICAgDQogICAgICAjIFJlc2lkdWFsIGFyZWEtc3BlY2lmaWMgbGlwIGNhbmNlciByaXNrIGR1ZSB0byB1bm9ic2VydmVkIGFuZCBzcGF0aWFsbHkgdW5zdHJ1Y3R1cmVkIGZhY3RvcnMgKHUpDQogICAgICANCiAgICAgIHJlc2lkdWFsLnNpci51W2ldIDwtIGV4cCh1W2ldKQ0KICAgICAgDQogICAgICAjIFBvc3RlcmlvciBwcm9iYWJpbGl0aWVzIGZvciByZXNpZHVhbCByaXNrIC0gaXMgdGhlIFNJUiBmb3IgdGhlIGl0aCBkaXN0cmljdCBoaWdoZXIgb3IgbG93ZXIgdGhhbiAxDQogICAgICANCiAgICAgIHJlc2lkdWFsLnNpci5ndDFbaV0gPC0gMSAtIHN0ZXAoMSAtIHJlc2lkdWFsLnNpcltpXSkgIyBQb3N0ZXJpb3IgcHJvYmFiaWxpdHkgdGhhdCBTSVIgPiAxDQogICAgICByZXNpZHVhbC5zaXIubHQxW2ldIDwtIDEgLSBzdGVwKHJlc2lkdWFsLnNpcltpXSAtIDEpICMgUG9zdGVyaW9yIHByb2JhYmlsaXR5IHRoYXQgU0lSIDwgMSAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICB9IA0KICAgIA0KICAgICMgUHJpb3IgZm9yIHRoZSBhcmVhLXNwZWNpZmljIHNwYXRpYWxseSBzdHJ1Y3R1cmVkIHJhbmRvbSBlZmZlY3QgKElDQVIpDQogICAgDQogICAgc1sxOk5dIH4gZGNhcl9ub3JtYWwoYWRqWzE6TF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgd2VpZ2h0c1sxOkxdLA0KICAgICAgICAgICAgICAgICAgICAgICAgIG51bVsxOk5dLA0KICAgICAgICAgICAgICAgICAgICAgICAgIHRhdS5zLA0KICAgICAgICAgICAgICAgICAgICAgICAgIHplcm9fbWVhbiA9IDEpDQogICAgDQogICAgIyBWYWd1ZSB1bmlmb3JtIHByaW9yIGZvciBpbnRlcmNlcHQNCiAgICANCiAgICBhbHBoYSB+IGRmbGF0KCkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICANCiAgICAjIE92ZXJhbGwgU0lSIGZvciB0aGUgc3R1ZHkgcmVnaW9uIChsaXAgY2FuY2VyIHJpc2sgY29tbW9uIHRvIGFsbCBhcmVhcykNCiAgICANCiAgICBvdmVyYWxsLnNpciA8LSBleHAoYWxwaGEpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICANCiAgICAjIEh5cGVycHJpb3IgZGlzdHJpYnV0aW9uIG9uIGludmVyc2UgdmFyaWFuY2UgKHByZWNpc2lvbikgZm9yIHRoZSB1bnN0cnVjdHVyZWQgdmFyaWFuY2UgY29tcG9uZW50ICh1KQ0KICAgIA0KICAgIHRhdS51IH4gZGdhbW1hKDEsIDAuMDEpICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgIA0KICAgICMgVmFyaWFuY2Ugb2YgdSAodW5zdHJ1Y3R1cmVkIHZhcmlhbmNlIGNvbXBvbmVudCkNCiAgICANCiAgICBzaWdtYTIudSA8LSAxL3RhdS51ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICANCiAgICAjIEh5cGVycHJpb3IgZGlzdHJpYnV0aW9uIG9uIGludmVyc2UgdmFyaWFuY2UgKHByZWNpc2lvbikgZm9yIHRoZSBzcGF0aWFsbHkgc3RydWN0dXJlZCB2YXJpYW5jZSBjb21wb25lbnQgKHMpDQogICAgDQogICAgdGF1LnMgfiBkZ2FtbWEoMSwgMC4wMSkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICANCiAgICAjIHZhcmlhbmNlIG9mIHMgKHNwYXRpYWwgdmFyaWFuY2UgY29tcG9uZW50KQ0KICAgIA0KICAgIHNpZ21hMi5zIDwtIDEvdGF1LnMNCiAgICANCiAgfQ0KKQ0KDQpiYXNlOjpwcmludChieW1fY29kZSkNCg0KIyMgU3BlY2lmeSBpbml0aWFsIHZhbHVlcyBmb3Igbm9kZXMgYXMgYSBkYXRhIGxpc3QgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyBhbHBoYSA9IGludGVyY2VwdA0KIyB1ICAgICA9IHByaW9yIGZvciB1bnN0cnVjdHVyZWQgcmFuZG9tIGVmZmVjdA0KIyB0YXUudSA9IGh5cGVycHJpb3IgZm9yIHRoZSBwcmVjaXNpb24gb2YgdQ0KIyBzICAgICA9IHByaW9yIGZvciBzdHJ1Y3R1cmVkIHJhbmRvbSBlZmZlY3QNCiMgdGF1LnMgPSBoeXBlcnByaW9yIGZvciB0aGUgcHJlY2lzaW9uIG9mIHMNCg0KYnltX2luaXRzIDwtIGxpc3QobGlzdChhbHBoYSA9IDAuMDEsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBNQ01DIGNoYWluIDEgDQogICAgICAgICAgICAgICAgICAgICAgIHUgPSBiYXNlOjpyZXAoMC4wMSwgdGltZXMgPSBOKSwgDQogICAgICAgICAgICAgICAgICAgICAgIHRhdS51ID0gMTAsDQogICAgICAgICAgICAgICAgICAgICAgIHMgPSBiYXNlOjpyZXAoMC4wMSwgdGltZXMgPSBOKSwNCiAgICAgICAgICAgICAgICAgICAgICAgdGF1LnMgPSAxMCksDQogICAgICAgICAgICAgICAgICBsaXN0KGFscGhhID0gMC41LCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIE1DTUMgY2hhaW4gMg0KICAgICAgICAgICAgICAgICAgICAgICB1ID0gYmFzZTo6cmVwKC0wLjAxLCB0aW1lcyA9IE4pLA0KICAgICAgICAgICAgICAgICAgICAgICB0YXUudSA9IDEsDQogICAgICAgICAgICAgICAgICAgICAgIHMgPSBiYXNlOjpyZXAoLTAuMDEsIHRpbWVzID0gTiksDQogICAgICAgICAgICAgICAgICAgICAgIHRhdS5zID0gMSkpDQoNCmJhc2U6OnByaW50KGJ5bV9pbml0cykNCg0KIyMgU2VsZWN0IHBhcmFtZXRlcnMgKG5vZGVzKSB0byBtb25pdG9yIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KYnltX3BhcmFtcyA8LSBjKCJhbHBoYSIsDQogICAgICAgICAgICAgICAgInUiLA0KICAgICAgICAgICAgICAgICJzIiwNCiAgICAgICAgICAgICAgICAic2lnbWEyLnMiLA0KICAgICAgICAgICAgICAgICJzaWdtYTIudSIsDQogICAgICAgICAgICAgICAgIm92ZXJhbGwuc2lyIiwNCiAgICAgICAgICAgICAgICAicmVzaWR1YWwuc2lyIiwNCiAgICAgICAgICAgICAgICAicmVzaWR1YWwuc2lyLnMiLA0KICAgICAgICAgICAgICAgICJyZXNpZHVhbC5zaXIudSIsDQogICAgICAgICAgICAgICAgInNtb290aGVkLnNpciIsDQogICAgICAgICAgICAgICAgInJlc2lkdWFsLnNpci5ndDEiLA0KICAgICAgICAgICAgICAgICJyZXNpZHVhbC5zaXIubHQxIikNCg0KcHJpbnQoYnltX3BhcmFtcykNCg0KIyMgU3BlY2lmeSB0aGUgTUNNQyBzYW1wbGVyIHNldHRpbmdzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0Kbl9jaGFpbnMgPC0gMiAgICAgICAgICAgICAjIE51bWJlciBvZiBNQ01DIGNoYWlucyB0byBydW4gIA0Kbl9idXJuaW4gPC0gNTAwMDAgICAgICAgICAjIE51bWJlciBvZiBpdGVyYXRpb25zIHRvIHVzZSBhcyBtb2RlbCBidXJuLWluDQpuX2l0ZXIgPC0gbl9idXJuaW4gKiAyICAgICMgTnVtYmVyIG9mIGl0ZXJhdGlvbnMgcGVyIGNoYWluDQpuX3RoaW4gPC0gMSAgICAgICAgICAgICAgIyBUaGlubmluZyBpbnRlcnZhbCBmb3IgY2hhaW4sIGkuZS4sIGtlZXAgZXZlcnkgbnRoIHNhbXBsZQ0KDQojIEJ1cm4taW4gc2FtcGxlcyBwZXIgY2hhaW4gKG4gPSAyKSAtIHVzZWQgdG8gY29udmVyZ2UgbW9kZWwNCg0KKG5fYnVybmluIC8gbl90aGluKSAgICAgICAgICAgICAgICAjIDUwMDAgc2FtcGxlcyB1c2VkIHRvIGJ1cm4gdGhlIG1vZGVsIGluDQoNCiMgSW5mZXJlbmNlIHNhbXBsZXMgcGVyIGNoYWluIChuID0gMikNCg0KKChuX2l0ZXIgLSBuX2J1cm5pbikgLyBuX3RoaW4pICAgICAjIDUwMDAgc2FtcGxlcyBmcm9tIHRoZSBwb3N0ZXJpb3IgZGlzdHJpYnV0aW9uIHN1bW1hcmlzZWQgZm9yIGluZmVyZW5jZQ0KDQojIyMgRml0IHRoZSBtb2RlbCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojIFRoZSBuaW1ibGUgc2hvd0NvbXBpbGVyT3V0cHV0IGFuZCBuaW1ibGVNQ01DIG9wdGlvbnMgYXJlIHNldCB0byBUUlVFIGZvcg0KIyBkZW1vbnN0cmF0aW9uIHB1cnBvc2VzIG9ubHkuIFlvdSBjYW4gZXhjbHVkZSB0aGVzZSBvcHRpb25zIGlmIHlvdSBwcmVmZXINCg0KbmltYmxlT3B0aW9ucyhzaG93Q29tcGlsZXJPdXRwdXQgPSBUUlVFKQ0KYnltX3NhbXBsZXMgPC0gbmltYmxlOjpuaW1ibGVNQ01DKGNvZGUgPSBieW1fY29kZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gYnltX2RhdGEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3RhbnRzID0gYnltX2NvbnN0cywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5pdHMgPSBieW1faW5pdHMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9uaXRvcnMgPSBieW1fcGFyYW1zLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5pdGVyID0gbl9pdGVyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5idXJuaW4gPSBuX2J1cm5pbiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGluID0gbl90aGluLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuY2hhaW5zID0gbl9jaGFpbnMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNldFNlZWQgPSBjKDksIDEwKSwgICAgICAgICAgICAgICMgU2VlZCBmb3IgcmFuZG9tZSBudW1iZXIgZ2VuZXJhdG9yIC0gaW1wb3J0YW50IGZvciByZXByb2R1Y2liaWxpdHkgLSBuZWVkIG9uZSBzZWVkIHBlciBjaGFpbiAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZ3Jlc3NCYXIgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhbXBsZXNBc0NvZGFNQ01DID0gVFJVRSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VtbWFyeSA9IFRSVUUsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFdBSUMgPSBUUlVFKQ0KbmltYmxlT3B0aW9ucyhzaG93Q29tcGlsZXJPdXRwdXQgPSBGQUxTRSkNCg0KIyBTZWUgaHR0cHM6Ly9zdGF0cy5zdGFja2V4Y2hhbmdlLmNvbS9xLzMwNDk1OCBmb3IgZGlzY3Vzc2lvbiBhYm91dCBXQUlDIHdhcm5pbmcNCg0KIyMgVmlldyByYXcgbGlzdCBvdXRwdXQgcmV0dXJuZWQgbXkgdGhlIE1DTUMgc2FtcGxlciAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyBTYW1wbGVkIHZhbHVlcyBmcm9tIHRoZSBwb3N0ZXJpb3IgZGlzdHJpYnV0aW9uIChuID0gbl9pdGVyIC0gbl9idXJpbiA9IDUsMDAwKQ0KDQp1dGlsczo6aGVhZChhcy5kYXRhLmZyYW1lLm1hdHJpeChieW1fc2FtcGxlcyRzYW1wbGVzJGNoYWluMSksIG4gPSAxMCkgDQoNCiMgU3VtbWFyaXNlZCBzYW1wbGUgdmFsdWVzIGZyb20gdGhlIHBvc3RlcmlvciBkaXN0cmlidXRpb24gKG1lYW4sIG1lZGlhbiwgc3RkIGFuZCBxdWFudGlsZXMgMi41IGFuZCA5Ny41KQ0KdXRpbHM6OmhlYWQoYnltX3NhbXBsZXMkc3VtbWFyeSRhbGwuY2hhaW5zLCBuID0gMTAwKQ0KDQojIyMgQ2hlY2sgbW9kZWwgY29udmVyZ2VuY2UgdXNpbmcgdGhlIEdlbG1hbi1SdWJpbiBjb252ZXJnZW5jZSBkaWFnbm9zdGljIC0tLS0tLQ0KDQojIFRoZSBHZWxtYW4tUnViaW4gY29tcGFyZXMgdGhlIHdpdGhpbiBjaGFpbiB2YXJpYXRpb24gdG8gdGhlIGJldHdlZW4gY2hhaW4NCiMgdmFyaWF0aW9uIGZvciBlYWNoIHBhcmFtZXRlci4gSWYgdGhlIGNoYWlucyBoYXZlIGNvbnZlcmdlZCBvbiB0aGUgc3RhdGlvbmFyeQ0KIyBkaXN0cmlidXRpb24sIHRoZW4gaXQgc2hvdWxkIGJlIGltcG9zc2libGUgdG8gZGlzdGluZ3Vpc2ggYmV0d2VlbiB0aGUgY2hhaW5zLg0KIyBJdCBpcyBhIHJhdGlvIG1lYXN1cmVzLCBhbmQgdmFsdWVzIDwgMS4xIGFyZSBjb25zaWRlcmVkIGV2aWRlbmNlIG9mIGNoYWluDQojIGNvbnZlcmdlbmNlLg0KDQojIGdyLmRpYWcgPC0gY29kYTo6Z2VsbWFuLmRpYWcoYnltX3NhbXBsZXMkc2FtcGxlcywgbXVsdGl2YXJpYXRlID0gRkFMU0UpDQojIA0KIyAjIExpc3QgYWxsIHBhcmFtZXRlcnMgdGhhdCBhcmUgbm90IHBvc3RlcmlvciBwcm9iYWJpbGl0aWVzDQojIA0KIyBnci5kaWFnLmluYyA8LSBzdHJpbmdyOjpzdHJfc3Vic2V0KGJhc2U6OmRpbW5hbWVzKGdyLmRpYWckcHNyZilbWzFdXSwgImd0MXxsdDEiLCBuZWdhdGUgPSBUUlVFKQ0KIyANCiMgIyMgQXJlIGFsbCB2YWx1ZXMgPCAxLjE/IElmIHllcywgdGhpcyBpcyBldmlkZW5jZSBvZiBjb252ZXJnZW5jZSAtLS0tLS0tLS0tLS0tLS0NCiMgDQojIGJhc2U6OmFsbChnci5kaWFnJHBzcmZbZ3IuZGlhZy5pbmMsIlBvaW50IGVzdC4iXSA8IDEuMSkgIyBEb24ndCBjaGVjayBwb3N0ZXJpb3IgcHJvYmFiaWxpdGllcyAtIHRoZXNlIGFyZSB0aHJlc2hvbGQgbm9kZXMgYW5kIGRvIG5vdCBuZWVkIHRvIGNvbnZlcmdlDQojIA0KIyAjIyBJZiBubywgdGhlbiBXaGljaCBwYXJhbWV0ZXJzIGhhdmUgYSB2YWx1ZSA+PSAxLjE/IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyANCiMgYmFzZTo6d2hpY2goZ3IuZGlhZyRwc3JmW2dyLmRpYWcuaW5jLCJQb2ludCBlc3QuIl0gPiAxLjEpDQoNCiMjIyBDaGVjayB0cmFjZSwgZGVuc2l0eSBhbmQgYXV0b2NvcnJlbGF0aW9uIHBsb3RzIGZvciBjb252ZXJnZW5jZSAtLS0tLS0tLS0tLS0tDQoNCiMgSW1wb3J0IE1DTUMgc2FtcGxlcyBpbnRvIGEgZ2dzIHRoYXQgY2FuIGJlIHVzZWQgd2l0aCBnZ3NfKiBncmFwaGljYWwgZnVuY3Rpb25zDQoNCmJ5bV9nZ21jbWMgPC0gZ2dtY21jOjpnZ3MoYnltX3NhbXBsZXMkc2FtcGxlcykNCg0KIyMgQ2hlY2sgdGhlIG92ZXJhbGwgU0lSIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyBHZW5lcmF0ZSB0cmFjZSwgZGVuc2l0eSBhbmQgYXV0b2NvcnJlbGF0aW9uIHBsb3RzDQoNCnRyYWNlX292ZXJhbGwuc2lyIDwtIGJ5bV9nZ21jbWMgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKFBhcmFtZXRlciA9PSAib3ZlcmFsbC5zaXIiKSAlPiUgDQogIGdnbWNtYzo6Z2dzX3RyYWNlcGxvdCgpICsNCiAgZ2dwbG90Mjo6dGhlbWVfYncoKSArDQogIGdncGxvdDI6OnRoZW1lKHRleHQgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoc2l6ZSA9IDEyKSkNCg0KZGVuc2l0eV9vdmVyYWxsLnNpciA8LSBieW1fZ2dtY21jICU+JSANCiAgZHBseXI6OmZpbHRlcihQYXJhbWV0ZXIgPT0gIm92ZXJhbGwuc2lyIikgJT4lIA0KICBnZ21jbWM6Omdnc19kZW5zaXR5KCkgKw0KICBnZ3Bsb3QyOjp0aGVtZV9idygpICsNCiAgZ2dwbG90Mjo6dGhlbWUodGV4dCA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChzaXplID0gMTIpKQ0KDQphY2Zfb3ZlcmFsbC5zaXIgPC0gYnltX2dnbWNtYyAlPiUNCiAgZHBseXI6OmZpbHRlcihQYXJhbWV0ZXIgPT0gIm92ZXJhbGwuc2lyIikgJT4lIA0KICBnZ21jbWM6Omdnc19hdXRvY29ycmVsYXRpb24oKSArDQogIGdncGxvdDI6OnRoZW1lX2J3KCkgKw0KICBnZ3Bsb3QyOjp0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikpDQoNCiMgUGxvdCB2aXN1YWwgY29udmVyZ2VuY2UgZGlhZ25vc3RpY3MNCg0KYmFzZTo6cHJpbnQoKHRyYWNlX292ZXJhbGwuc2lyIHwgZGVuc2l0eV9vdmVyYWxsLnNpcikgLyBhY2Zfb3ZlcmFsbC5zaXIpICsNCiAgcGF0Y2h3b3JrOjpwbG90X2Fubm90YXRpb24odGl0bGUgPSAiVHJhY2UsIGRlbnNpdHkgYW5kIGF1dG9jb3JyZWxhdGlvbiBwbG90cyBmb3Igb3ZlcmFsbCBTSVIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZSA9IGdncGxvdDI6OnRoZW1lKHBsb3QudGl0bGUgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSkNCg0KIyMgQ2hlY2sgdGhlIHNwYXRpYWxseSB2YXJpYW5jZSBjb21wb25lbnQgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyBHZW5lcmF0ZSB0cmFjZSwgZGVuc2l0eSBhbmQgYXV0b2NvcnJlbGF0aW9uIHBsb3RzDQoNCnRyYWNlX3NpZ21hMi5zIDwtIGJ5bV9nZ21jbWMgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKFBhcmFtZXRlciA9PSAic2lnbWEyLnMiKSAlPiUgDQogIGdnbWNtYzo6Z2dzX3RyYWNlcGxvdCgpICsNCiAgZ2dwbG90Mjo6dGhlbWVfYncoKSArDQogIGdncGxvdDI6OnRoZW1lKHRleHQgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoc2l6ZSA9IDEyKSkNCg0KZGVuc2l0eV9zaWdtYTIucyA8LSBieW1fZ2dtY21jICU+JSANCiAgZHBseXI6OmZpbHRlcihQYXJhbWV0ZXIgPT0gInNpZ21hMi5zIikgJT4lIA0KICBnZ21jbWM6Omdnc19kZW5zaXR5KCkgKw0KICBnZ3Bsb3QyOjp0aGVtZV9idygpICsNCiAgZ2dwbG90Mjo6dGhlbWUodGV4dCA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChzaXplID0gMTIpKQ0KDQphY2Zfc2lnbWEyLnMgPC0gYnltX2dnbWNtYyAlPiUNCiAgZmlsdGVyKFBhcmFtZXRlciA9PSAic2lnbWEyLnMiKSAlPiUgDQogIGdnbWNtYzo6Z2dzX2F1dG9jb3JyZWxhdGlvbigpICsNCiAgZ2dwbG90Mjo6dGhlbWVfYncoKSArDQogIGdncGxvdDI6OnRoZW1lKHRleHQgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoc2l6ZSA9IDEyKSkNCg0KIyBQbG90IHZpc3VhbCBjb252ZXJnZW5jZSBkaWFnbm9zdGljcw0KDQpiYXNlOjpwcmludCgodHJhY2Vfc2lnbWEyLnMgfCBkZW5zaXR5X3NpZ21hMi5zKS9hY2Zfc2lnbWEyLnMpICsNCiAgcGF0Y2h3b3JrOjpwbG90X2Fubm90YXRpb24odGl0bGUgPSAiVHJhY2UsIGRlbnNpdHkgYW5kIGF1dG9jb3JyZWxhdGlvbiBwbG90cyBmb3Igc3BhdGlhbGx5IGNvcnJlbGF0ZWQgdmFyaWFuY2UgY29tcG9uZW50IChzKSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lID0gZ2dwbG90Mjo6dGhlbWUocGxvdC50aXRsZSA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpKQ0KDQojIyBDaGVjayB0aGUgdW5jb3JyZWxhdGVkIHZhcmlhbmNlIGNvbXBvbmVudCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojIEdlbmVyYXRlIHRyYWNlLCBkZW5zaXR5IGFuZCBhdXRvY29ycmVsYXRpb24gcGxvdHMNCg0KdHJhY2Vfc2lnbWEyLnUgPC0gYnltX2dnbWNtYyAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoUGFyYW1ldGVyID09ICJzaWdtYTIudSIpICU+JSANCiAgZ2dtY21jOjpnZ3NfdHJhY2VwbG90KCkgKw0KICBnZ3Bsb3QyOjp0aGVtZV9idygpICsNCiAgZ2dwbG90Mjo6dGhlbWUodGV4dCA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChzaXplID0gMTIpKQ0KDQpkZW5zaXR5X3NpZ21hMi51IDwtIGJ5bV9nZ21jbWMgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKFBhcmFtZXRlciA9PSAic2lnbWEyLnUiKSAlPiUgDQogIGdnbWNtYzo6Z2dzX2RlbnNpdHkoKSArDQogIGdncGxvdDI6OnRoZW1lX2J3KCkgKw0KICBnZ3Bsb3QyOjp0aGVtZSh0ZXh0ID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KHNpemUgPSAxMikpDQoNCmFjZl9zaWdtYTIudSA8LSBieW1fZ2dtY21jICU+JQ0KICBmaWx0ZXIoUGFyYW1ldGVyID09ICJzaWdtYTIudSIpICU+JSANCiAgZ2dtY21jOjpnZ3NfYXV0b2NvcnJlbGF0aW9uKCkgKw0KICBnZ3Bsb3QyOjp0aGVtZV9idygpICsNCiAgZ2dwbG90Mjo6dGhlbWUodGV4dCA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChzaXplID0gMTIpKQ0KDQpiYXNlOjpwcmludCgodHJhY2Vfc2lnbWEyLnUgfCBkZW5zaXR5X3NpZ21hMi51KSAvYWNmX3NpZ21hMi51KSArDQogIHBhdGNod29yazo6cGxvdF9hbm5vdGF0aW9uKHRpdGxlID0gIlRyYWNlLCBkZW5zaXR5IGFuZCBhdXRvY29ycmVsYXRpb24gcGxvdHMgZm9yIHVuY29ycmVsYXRlZCB2YXJpYW5jZSBjb21wb25lbnQgKHUpIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUgPSBnZ3Bsb3QyOjp0aGVtZShwbG90LnRpdGxlID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkpDQoNCiMjIENoZWNrIHRoZSBzbW9vdGhlZCBTSVIgZm9yIFBlcnRoLUtpbnJvc3MgKDI5KSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCiMgVGhpcyBkaXN0cmljdCBoYXMgdGhlIG1vc3QgbmVpZ2hib3Vycw0KDQojIEdlbmVyYXRlIHRyYWNlLCBkZW5zaXR5IGFuZCBhdXRvY29ycmVsYXRpb24gcGxvdHMNCg0KdHJhY2Vfc21vb3RoZWQuc2lyXzI5IDwtIGJ5bV9nZ21jbWMgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKFBhcmFtZXRlciA9PSAic21vb3RoZWQuc2lyWzI5XSIpICU+JSANCiAgZ2dtY21jOjpnZ3NfdHJhY2VwbG90KCkgKw0KICBnZ3Bsb3QyOjp0aGVtZV9idygpICsNCiAgZ2dwbG90Mjo6dGhlbWUodGV4dCA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChzaXplID0gMTIpKQ0KDQpkZW5zaXR5X3Ntb290aGVkLnNpcl8yOSA8LSBieW1fZ2dtY21jICU+JSANCiAgZHBseXI6OmZpbHRlcihQYXJhbWV0ZXIgPT0gInNtb290aGVkLnNpclsyOV0iKSAlPiUgDQogIGdnbWNtYzo6Z2dzX2RlbnNpdHkoKSArDQogIGdncGxvdDI6OnRoZW1lX2J3KCkgKw0KICBnZ3Bsb3QyOjp0aGVtZSh0ZXh0ID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KHNpemUgPSAxMikpDQoNCmFjZl9zbW9vdGhlZC5zaXJfMjkgPC0gYnltX2dnbWNtYyAlPiUNCiAgZmlsdGVyKFBhcmFtZXRlciA9PSAic21vb3RoZWQuc2lyWzI5XSIpICU+JSANCiAgZ2dtY21jOjpnZ3NfYXV0b2NvcnJlbGF0aW9uKCkgKw0KICBnZ3Bsb3QyOjp0aGVtZV9idygpICsNCiAgZ2dwbG90Mjo6dGhlbWUodGV4dCA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChzaXplID0gMTIpKQ0KDQojIFBsb3QgdmlzdWFsIGNvbnZlcmdlbmNlIGRpYWdub3N0aWNzDQoNCmJhc2U6OnByaW50KCh0cmFjZV9zbW9vdGhlZC5zaXJfMjkgfCBkZW5zaXR5X3Ntb290aGVkLnNpcl8yOSkgLyBhY2Zfc21vb3RoZWQuc2lyXzI5KSArDQogIHBhdGNod29yazo6cGxvdF9hbm5vdGF0aW9uKHRpdGxlID0gIlRyYWNlLCBkZW5zaXR5IGFuZCBhdXRvY29ycmVsYXRpb24gcGxvdHMgZm9yIFBlcnRoLUtpbnJvc3Mgc21vb3RoZWQgU0lSIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUgPSBnZ3Bsb3QyOjp0aGVtZShwbG90LnRpdGxlID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkpDQoNCiMjIyBTdW1tYXJpc2UgYWNyb3NzIE1DTUMgc2FtcGxlcyB0byBvYnRhaW5lZCBCWU0gbW9kZWwgZXN0aW1hdGVzIC0tLS0tLS0tLS0tLS0tDQoNCiMjIEV4dHJhY3QgYWxwaGEsIHNpZ21hMi5zIGFuZCBzaWdtYTIudSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCmJ5bV9lc3RzIDwtIGJ5bV9zYW1wbGVzJHN1bW1hcnkkYWxsLmNoYWluc1tjKCJhbHBoYSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAic2lnbWEyLnMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInNpZ21hMi51IiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYygiTWVkaWFuIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI5NSVDSV9sb3ciLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjk1JUNJX3VwcCIpXSAlPiUNCiAgDQogICMgQ29udmVydCBtYXRyaXggdG8gZGF0YSBmcmFtZQ0KICANCiAgYmFzZTo6YXMuZGF0YS5mcmFtZSgpICU+JQ0KICANCiAgIyBSZW5hbWUgY29sdW1ucw0KICANCiAgc3RhdHM6OnNldE5hbWVzKGMoIm1lZGlhbiIsICJsb3dlcl85NV9jaSIsICJ1cHBlcl85NV9jaSIpKSAlPiUNCiAgDQogICMgTWFrZSB0aGUgZGF0YSBmcmFtZSByb3cgbmFtZXMgYW4gZXhwbGljaXQgdmFyaWFibGUgY2FsbGVkICpwYXJhbWV0ZXIqDQogIA0KICB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAicGFyYW1ldGVyIikgJT4lDQogIA0KICAjIEV4cG9uZW50aWF0ZSB0aGUgcGFyYW1ldGVyIGFuZCA5NSUgQ0kgZXN0aW1hdGVzIGZvciBhbHBoYSB0byBvYnRhaW4gb3ZlcmFsbCBTSVIgZWZmZWN0IG1lYXN1cmUNCiAgDQogIGRwbHlyOjptdXRhdGUoZHBseXI6OmFjcm9zcyhjKG1lZGlhbiwgbG93ZXJfOTVfY2ksIHVwcGVyXzk1X2NpKSwgfiBiYXNlOjppZmVsc2UocGFyYW1ldGVyID09ICJhbHBoYSIsIGJhc2U6OmV4cCguKSwgTkEpLCAubmFtZXMgPSAiey5jb2x9X2V4cCIpKSAlPiUNCiAgDQogICMgRm9ybWF0IGVzdGltYXRlcyBhcyB0ZXh0IHZhcmlhYmxlcyB3aXRoIHRocmVlIGRlY2ltYWwgcGxhY2VzDQogIA0KICBkcGx5cjo6bXV0YXRlKGRwbHlyOjphY3Jvc3MoZHBseXI6OndoZXJlKGlzLm51bWVyaWMpLCB+IGJhc2U6OmlmZWxzZShiYXNlOjppcy5uYSguKSwgIiIsIGJhc2U6OmZvcm1hdChiYXNlOjpyb3VuZCguLCAzKSwgbnNtYWxsID0gMykpKSkNCg0KIyMjIFByaW50IG1vZGVsIGVzdGltYXRlcyBhbmQgV0lBQyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KYmFzZTo6cHJpbnQobGlzdCgiTW9kZWwgZXN0aW1hdGUiID0gYnltX2VzdHMsDQogICAgICAgICAgICAgICAgICJXQUlDIiA9IGJ5bV9zYW1wbGVzJFdBSUMkV0FJQykpDQoNCiMjIyBTdW1tYXJpc2UgYWNyb3NzIE1DTUMgc2FtcGxlcyB0byBvYnRhaW4gc21vb3RoZWQgU0lSIGVzdGltYXRlcyAtLS0tLS0tLS0tLS0tDQoNCiMgQ3JlYXRlIGRhdGEgc2V0IG9mIHNtb290aGVkIGFuZCByZXNpZHVhbCByaXNrIG9mIGxpcCBjYW5jZXINCg0KYnltX3NmIDwtIGxpcF9zZiAlPiUNCiAgDQogICMgU21vb3RoZWQgU0lSIGVzdGltYXRlDQogIA0KICBkcGx5cjo6YmluZF9jb2xzKGJ5bV9zYW1wbGVzJHN1bW1hcnkkYWxsLmNoYWluc1tiYXNlOjpwYXN0ZTAoInNtb290aGVkLnNpclsiLCAxOk4sICJdIiksIGMoIk1lZGlhbiIsICI5NSVDSV9sb3ciLCAiOTUlQ0lfdXBwIildICU+JQ0KICAgICAgICAgICAgICAgICAgICAgYmFzZTo6YXMuZGF0YS5mcmFtZSgpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgc3RhdHM6OnNldE5hbWVzKGMoImJ5bV9zbW9vdGhlZF9zaXJfZXN0IiwgImJ5bV9zbW9vdGhlZF9zaXJfbDk1IiwgImJ5bV9zbW9vdGhlZF9zaXJfdWNpIikpKSAlPiUNCiAgDQogICMgUmVzaWR1YWwgU0lSIGVzdGltYXRlDQogIA0KICBkcGx5cjo6YmluZF9jb2xzKGJ5bV9zYW1wbGVzJHN1bW1hcnkkYWxsLmNoYWluc1tiYXNlOjpwYXN0ZTAoInJlc2lkdWFsLnNpclsiLCAxOk4sICJdIiksIGMoIk1lZGlhbiIsICI5NSVDSV9sb3ciLCAiOTUlQ0lfdXBwIildICU+JQ0KICAgICAgICAgICAgICAgICAgICAgYmFzZTo6YXMuZGF0YS5mcmFtZSgpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgc3RhdHM6OnNldE5hbWVzKGMoImJ5bV9yZXNpZHVhbF9zaXJfZXN0IiwgImJ5bV9yZXNpZHVhbF9zaXJfbDk1IiwgImJ5bV9yZXNpZHVhbF9zaXJfdWNpIikpKSAlPiUNCiAgDQogICMgUmVzaWR1YWwgcyBTSVIgZXN0aW1hdGUNCiAgDQogIGRwbHlyOjpiaW5kX2NvbHMoYnltX3NhbXBsZXMkc3VtbWFyeSRhbGwuY2hhaW5zW2Jhc2U6OnBhc3RlMCgicmVzaWR1YWwuc2lyLnNbIiwgMTpOLCAiXSIpLCBjKCJNZWRpYW4iLCAiOTUlQ0lfbG93IiwgIjk1JUNJX3VwcCIpXSAlPiUNCiAgICAgICAgICAgICAgICAgICAgIGJhc2U6OmFzLmRhdGEuZnJhbWUoKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgIHN0YXRzOjpzZXROYW1lcyhjKCJieW1fcmVzaWR1YWxfc2lyX3NfZXN0IiwgImJ5bV9yZXNpZHVhbF9zaXJfc19sOTUiLCAiYnltX3Jlc2lkdWFsX3Npcl9zX3VjaSIpKSkgJT4lDQogIA0KICAjIFJlc2lkdWFsIHUgU0lSIGVzdGltYXRlDQogIA0KICBkcGx5cjo6YmluZF9jb2xzKGJ5bV9zYW1wbGVzJHN1bW1hcnkkYWxsLmNoYWluc1tiYXNlOjpwYXN0ZTAoInJlc2lkdWFsLnNpci51WyIsIDE6TiwgIl0iKSwgYygiTWVkaWFuIiwgIjk1JUNJX2xvdyIsICI5NSVDSV91cHAiKV0gJT4lDQogICAgICAgICAgICAgICAgICAgICBiYXNlOjphcy5kYXRhLmZyYW1lKCkgJT4lDQogICAgICAgICAgICAgICAgICAgICBzdGF0czo6c2V0TmFtZXMoYygiYnltX3Jlc2lkdWFsX3Npcl91X2VzdCIsICJieW1fcmVzaWR1YWxfc2lyX3VfbDk1IiwgImJ5bV9yZXNpZHVhbF9zaXJfdV91Y2kiKSkpICU+JQ0KICANCiAgIyBQb3N0ZXJpb3IgcHJvYmFiaWxpdGllcyBmb3IgcmVzaWR1YWwgcmlzayA+IDENCiAgDQogIGRwbHlyOjpiaW5kX2NvbHMoYnltX3NhbXBsZXMkc3VtbWFyeSRhbGwuY2hhaW5zW2Jhc2U6OnBhc3RlMCgicmVzaWR1YWwuc2lyLmd0MVsiLCAxOk4sICJdIiksICJNZWFuIl0gJT4lDQogICAgICAgICAgICAgICAgICAgICBiYXNlOjphcy5kYXRhLmZyYW1lKCkgJT4lDQogICAgICAgICAgICAgICAgICAgICBzdGF0czo6c2V0TmFtZXMoImJ5bV9yZXNpZHVhbF9zaXJfZ3QxIikpICU+JQ0KICANCiAgIyBQb3N0ZXJpb3IgcHJvYmFiaWxpdGllcyBmb3IgcmVzaWR1YWwgcmlzayA8IDENCiAgDQogIGRwbHlyOjpiaW5kX2NvbHMoYnltX3NhbXBsZXMkc3VtbWFyeSRhbGwuY2hhaW5zW2Jhc2U6OnBhc3RlMCgicmVzaWR1YWwuc2lyLmx0MVsiLCAxOk4sICJdIiksICJNZWFuIl0gJT4lDQogICAgICAgICAgICAgICAgICAgICBiYXNlOjphcy5kYXRhLmZyYW1lKCkgJT4lDQogICAgICAgICAgICAgICAgICAgICBzdGF0czo6c2V0TmFtZXMoImJ5bV9yZXNpZHVhbF9zaXJfbHQxIikpICU+JQ0KICANCiAgIyBBbm5vdGF0ZSBleGNlZWRlbmNlIHByb2JhYmlsaXRpZXMNCiAgDQogIGRwbHlyOjptdXRhdGUoYnltX3Jlc2lkdWFsX3Npcl9jYXQgPSBkcGx5cjo6Y2FzZV93aGVuKGJ5bV9yZXNpZHVhbF9zaXJfZ3QxID4gMC45OTUgfiAiKysiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBieW1fcmVzaWR1YWxfc2lyX2d0MSA+IDAuOTc1IH4gIisiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBieW1fcmVzaWR1YWxfc2lyX2x0MSA+IDAuOTk1IH4gIi0tIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnltX3Jlc2lkdWFsX3Npcl9sdDEgPiAwLjk3NSB+ICItIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmRlZmF1bHQgPSAiIikpDQoNCiMjIyBNYXAgQllNIHNtb290aGVkIFNJUiBmb3IgZGlzdHJpY3RzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCm1hcF9ieW1fcmVzaWR1YWxfc2lyIDwtIGdncGxvdCgpICsNCiAgDQogICMgQWRkIFNJUiBlc3RpbWF0ZXMNCiAgDQogIGdlb21fc2YoZGF0YSA9IGJ5bV9zZiwNCiAgICAgICAgICBhZXMoZmlsbCA9IGJ5bV9yZXNpZHVhbF9zaXJfZXN0KSwNCiAgICAgICAgICBjb2wgPSAiZ3JleTUwIiwNCiAgICAgICAgICBsaW5ld2lkdGggPSAwLjEpICsNCiAgDQogICMgQWRkIFNJUiBwb3N0ZXJpb3IgcHJvYmFiaWxpdGllcw0KICANCiAgZ2dwbG90Mjo6Z2VvbV9wb2ludChkYXRhID0gYnltX3NmICU+JSBkcGx5cjo6ZmlsdGVyKGJ5bV9yZXNpZHVhbF9zaXJfY2F0ICE9ICIiKSwNCiAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gZ2dwbG90Mjo6YWVzKHNoYXBlID0gYnltX3Jlc2lkdWFsX3Npcl9jYXQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tZXRyeSA9IGdlb20pLA0KICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgIHN0YXQgPSAic2ZfY29vcmRpbmF0ZXMiKSArDQogIA0KICAjIEFkZCBTY290bGFuZCBib3VuZGFyeQ0KICANCiAgZ2dwbG90Mjo6Z2VvbV9zZihkYXRhID0gc2N0X3NmLA0KICAgICAgICAgICAgICAgICAgIGZpbGwgPSBOQSwNCiAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSAiQmxhY2siLA0KICAgICAgICAgICAgICAgICAgIGxpbmV3aWR0aCA9IDEpICsNCiAgDQogICMgQWRkIGZpbGwgYWVzdGhldGljIGdyYWRpZW50IG1hcHBpbmcNCiAgDQogIGdncGxvdDI6OnNjYWxlX2ZpbGxfZ3JhZGllbnQyKCJTbW9vdGhlZCBTSVIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3cgPSBjb2xfcGFsWyJsb3ciXSwgIyBibHVlDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pZCA9IGNvbF9wYWxbIm1pZCJdLCAjIHllbGxvdw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoaWdoID0gY29sX3BhbFsiaGlnaCJdLCAjIGRhcmtibHVlDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pZHBvaW50ID0gMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEudmFsdWUgPSBOQSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYyhiYXNlOjpleHAoLW1heF9sb2dfc2lyKSwgYmFzZTo6ZXhwKG1heF9sb2dfc2lyKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGJhc2U6OmV4cChiYXNlOjpzZXEoLW1heF9sb2dfc2lyLCBtYXhfbG9nX3NpciwgMC41KSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGJhc2U6OmZvcm1hdChiYXNlOjpyb3VuZChleHAoc2VxKC1tYXhfbG9nX3NpciwgbWF4X2xvZ19zaXIsIDAuNSkpLCAyKSwgbnNtYWxsID0gMiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zID0gImxvZyIpICsNCiAgDQogICMgQWRkIHNoYXBlIGFlc3RoaWMgbWFwcGluZw0KICANCiAgZ2dwbG90Mjo6c2NhbGVfc2hhcGVfbWFudWFsKCJQb3N0ZXJpb3IgcHJvYmFiaWxpdGllcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCIrKyIgPSAyNCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIisiID0gMiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIi0iID0gNiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIi0tIiA9IDI1KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGMoIisrIiwgIisiLCAiLSIsICItLSIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiKysiID0gIlNJUiA+IDEsIHAgPiA5Ny41JSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIrIiA9ICJTSVIgPiAxLCBwID4gOTUuMCUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiLSIgPSAiU0lSIDwgMSwgcCA+IDk1LjAlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIi0tIiA9ICJTSVIgPCAxLCBwID4gOTcuNSUiKSkgKw0KICANCiAgIyBGb3JtYXQgbGVnZW5kcw0KICANCiAgZ3VpZGVzKGZpbGwgPSBndWlkZV9jb2xvdXJiYXIoZnJhbWUuY29sb3VyID0gImJsYWNrIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZyYW1lLmxpbmV3aWR0aCA9IDAuMjUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpY2tzLmNvbG91ciA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpY2tzLmxpbmV3aWR0aCA9IDAuMjUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yZGVyID0gMSksDQogICAgICAgICBzaGFwZSA9IGd1aWRlX2xlZ2VuZChvcmRlciA9IDIpKSArDQogIA0KICAjIEZvcm1hdCBtYXANCiAgDQogIHRoZW1lX2J3KCkgKyANCiAgDQogIHRoZW1lKGF4aXMudGl0bGUgPSBnZ3Bsb3QyOjplbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGV4dCA9IGdncGxvdDI6OmVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50aWNrcyA9IGdncGxvdDI6OmVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJpbnNpZGUiLA0KICAgICAgICBsZWdlbmQubWFyZ2luID0gZ2dwbG90Mjo6bWFyZ2luKDAsIDAsIDAsIDApLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24uaW5zaWRlID0gYygwLjE1LCAwLjg4KSwNCiAgICAgICAgDQogICAgICAgIHBhbmVsLmdyaWQgPSBnZ3Bsb3QyOjplbGVtZW50X2JsYW5rKCksDQogICAgICAgIA0KICAgICAgICB0ZXh0ID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KHNpemUgPSAxMikpDQoNCiMjIE91dHB1dCBvYnNlcnZlZCBhbmQgQllNIHNtb290aGVkIFNJUiBmb3IgbGlwIGNhbmNlciByaXNrIC0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCihtYXBfb2JzX3NpciB8IG1hcF9ieW1fcmVzaWR1YWxfc2lyKSArDQogIHBhdGNod29yazo6cGxvdF9hbm5vdGF0aW9uKHRpdGxlID0gIk9ic2VydmVkIGFuZCBCWU0gc21vb3RoZWQgU0lSIGZvciBtYWxlIGxpcCBjYW5jZXIgaW4gU2NvdGxhbmQgKDE5NzUtMTk4MCkiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUgPSB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkpDQoNCmBgYA0KDQojIyBSZWZlcmVuY2VzDQoNCjxwIGNsYXNzPSJubG0tcmVmZXJlbmNlIj5DbGF5dG9uIEQsIEthbGRvciBKLiBFbXBpcmljYWwgQmF5ZXMgZXN0aW1hdGVzIG9mIGFnZSBzdGFuZGFyZGlzZWQgcmVsYXRpdmUgcmlza3MgZm9yIHVzZSBpbiBkaXNlYXNlIG1hcHBpbmcuIEJpb21ldHJpY3MgMTk4Nzs0Mzo2NzEtLTY4MS4gZG9pOiBbMTAuMjMwNy8yNTMyMDAzXShodHRwczovL2RvaS5vcmcvMTAuMjMwNy8yNTMyMDAzKTwvcD4NCg0KPHAgY2xhc3M9Im5sbS1yZWZlcmVuY2UiPkNyZXNzaWUgTkFDLiBTdGF0aXN0aWNzIGZvciBzcGF0aWFsIGRhdGEuIE5ldyBZb3JrOiBKb2huIFdpbGV5ICYgU29uczsgMTk5My4gcC4gNTM3IChUYWJsZSA3LjIpLiBkb2k6IFsxMC4xMDAyLzk3ODExMTkxMTUxNTFdKGh0dHBzOi8vZG9pLm9yZy8xMC4xMDAyLzk3ODExMTkxMTUxNTEpPC9wPg0KDQo8cCBjbGFzcz0ibmxtLXJlZmVyZW5jZSI+U3Rlcm4gSCwgQ3Jlc3NpZSBOLiBJbmZlcmVuY2VzIGZvciBleHRyZW1lcyBpbiBkaXNlYXNlIG1hcHBpbmcuIEluIExhd3NvbiBBQiwgQmlnZ2VyaSBBLCBCw7ZobmluZyBELCBldCBhbC4sIGVkaXRvcnMuIERpc2Vhc2UgbWFwcGluZyBhbmQgcmlzayBhc3Nlc3NtZW50IGZvciBwdWJsaWMgaGVhbHRoLiBOZXcgWW9yazogV2lsZXk7IDE5OTkuIHBwLiA2OC0tNjkgKFRhYmxlIDUuMSkuIEF2YWlsYWJsZSBhdCBTdG9yYWdlIEdlbmVyYWwgKFs2MTQuNDIgNDFdKGh0dHBzOi8vc3lkbmV5LnByaW1vLmV4bGlicmlzZ3JvdXAuY29tL3Blcm1hbGluay82MVVTWURfSU5TVC8xYzB1ZzQ4L2FsbWE5OTEwMDY0OTA2Mzk3MDUxMDYpKTwvcD4NCg==